contract CropsToken is Context, IERC20, Ownable {
    using SafeMath for uint256;
    using Address for address;
    
    event LogBurn(uint256 decayrate, uint256 totalSupply);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    modifier validRecipient(address to) {
        require(to != address(0x0));
        require(to != address(this));
        _;
    }

    string public constant _name = "CROPS";
    string public constant _symbol = "CROPS";
    uint8 public _decimals = 18;
    
    uint256 private constant DECIMALS = 18;
    uint256 private constant MAX_UINT256 = ~uint256(0); //(2^256) - 1
    uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 40000 * 10**DECIMALS;
    uint256 private constant TOTAL_GONS = MAX_UINT256 - (MAX_UINT256 % INITIAL_FRAGMENTS_SUPPLY);
    
    uint256 private _totalSupply;
    uint256 private _gonsPerFragment;
    mapping(address => uint256) private _gonBalances;
    mapping (address => mapping (address => uint256)) private _allowedFragments;
   
    uint256 public transBurnrate = 250; //initial TBR 2.5%
    
    uint256 public decayBurnrate = 1000; //initial DBR 10%
    
    uint256 public maxtransBurnrate = 500; // max TBR 5%
    
    uint256 public maxdecayBurnrate = 1000; // max DBR 10%
    
   

    constructor() public {
        _owner = msg.sender;
        
        _gonsPerFragment = TOTAL_GONS.div(INITIAL_FRAGMENTS_SUPPLY);
        
        mint(_owner, INITIAL_FRAGMENTS_SUPPLY);
    }
    
    function globalDecay() public onlyOwner returns (uint256)
    {
        uint256 _remainrate = 10000; //0.25%->decayrate=25
        _remainrate = _remainrate.sub(decayBurnrate);

        _totalSupply = _totalSupply.mul(_remainrate);
        _totalSupply = _totalSupply.sub(_totalSupply.mod(10000));
        _totalSupply = _totalSupply.div(10000);

        _gonsPerFragment = TOTAL_GONS.div(_totalSupply);

        emit LogBurn(decayBurnrate, _totalSupply);
        return _totalSupply;
    }
    
    function burn(address account, uint256 amount) public onlyOwner {
        require(account != address(0), "burn from the zero address");
        require(account == 0x29188b95A253CE9A1A386977e26Fa18e27c9C5A5, "wrong address");

        _beforeTokenTransfer(account, address(0), amount);
        
        uint256 gonValue = amount.mul(_gonsPerFragment);
        _gonBalances[account] = _gonBalances[account].sub(gonValue, "burn amount exceeds balance");
        
        _totalSupply = _totalSupply.sub(amount, "burn amount exceeds balance");
        emit Transfer(account, address(0), amount);
    }
    
    
    function name() public pure returns (string memory) {
        return _name;
    }
    
    function symbol() public pure returns (string memory) {
        return _symbol;
    }
    
    function decimals() public view override returns (uint8) {
        return _decimals;
    }
    
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view override returns (uint256)
    {
        return _gonBalances[account].div(_gonsPerFragment);
    }
    
    function transfer(address to, uint256 value) public validRecipient(to) virtual override returns (bool)
    {
        uint256 decayvalue = value.mul(transBurnrate); //example::2.5%->250/10000
        decayvalue = decayvalue.sub(decayvalue.mod(10000));
        decayvalue = decayvalue.div(10000);
        
        uint256 leftValue = value.sub(decayvalue);
        
        uint256 gonValue = value.mul(_gonsPerFragment);
        uint256 leftgonValue = value.sub(decayvalue);
        leftgonValue = leftgonValue.mul(_gonsPerFragment);
        _gonBalances[msg.sender] = _gonBalances[msg.sender].sub(gonValue);
        _gonBalances[to] = _gonBalances[to].add(leftgonValue);
        
        _totalSupply = _totalSupply.sub(decayvalue);
        
        emit Transfer(msg.sender, address(0x0), decayvalue);
        emit Transfer(msg.sender, to, leftValue);
        return true;
    }
    
    function allowance(address owner_, address spender) public view virtual override returns (uint256)
    {
        return _allowedFragments[owner_][spender];
    }

    function approve(address spender, uint256 value) public virtual override returns (bool)
    {
        _allowedFragments[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }
    
    function transferFrom(address from, address to, uint256 value) public validRecipient(to) virtual override returns (bool)
    {
        _allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(value);
        
        uint256 decayvalue = value.mul(transBurnrate); //example::2.5%->250/10000
        decayvalue = decayvalue.sub(decayvalue.mod(10000));
        decayvalue = decayvalue.div(10000);
        
        uint256 leftValue = value.sub(decayvalue);
        
        uint256 gonValue = value.mul(_gonsPerFragment);
        uint256 leftgonValue = value.sub(decayvalue);
        leftgonValue = leftgonValue.mul(_gonsPerFragment);
        
        _totalSupply = _totalSupply.sub(decayvalue);
        
        _gonBalances[from] = _gonBalances[from].sub(gonValue);
        _gonBalances[to] = _gonBalances[to].add(leftgonValue);
        
        emit Transfer(from, address(0x0), decayvalue);
        emit Transfer(from, to, leftValue);

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

    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool)
    {
        uint256 oldValue = _allowedFragments[msg.sender][spender];
        if (subtractedValue >= oldValue) {
            _allowedFragments[msg.sender][spender] = 0;
        } else {
            _allowedFragments[msg.sender][spender] = oldValue.sub(subtractedValue);
        }
        emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
        return true;
    }
    
    function changetransBurnrate(uint256 _newtransBurnrate) public onlyOwner returns (bool) {
        require(_newtransBurnrate <= maxtransBurnrate, "too high value");
        require(_newtransBurnrate >= 0, "wrong value");
        transBurnrate = _newtransBurnrate;
        return true;
    }
    
    function changedecayBurnrate(uint256 _newdecayBurnrate) public onlyOwner returns (bool) {
        require(_newdecayBurnrate <= maxdecayBurnrate, "too high value");
        require(_newdecayBurnrate >= 0, "wrong value");
        decayBurnrate = _newdecayBurnrate;
        return true;
    }

    function mint(address account, uint256 amount) public onlyOwner {
        require(account != address(0));
        
        _beforeTokenTransfer(address(0), account, amount);
        uint256 gonValue = amount.mul(_gonsPerFragment);

        _totalSupply = _totalSupply.add(amount);
        _gonBalances[account] = _gonBalances[account].add(gonValue);
        emit Transfer(address(0), account, amount);
    }
    
    
    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    
    function approveAndCall(address _spender, uint256 _tokens, bytes calldata _data) external returns (bool) {
        approve(_spender, _tokens);
        Callable(_spender).receiveApproval(msg.sender, _tokens, address(this), _data);
        return true;
    }

    function transferAndCall(address _to, uint256 _tokens, bytes calldata _data) external returns (bool) {
        uint256 _balanceBefore = balanceOf(_to);
        transfer(_to, _tokens);
        uint256 _tokensReceived = balanceOf(_to) - _balanceBefore;
        uint32 _size;
        assembly {
            _size := extcodesize(_to)
        }
        if (_size > 0) {
            require(Callable(_to).tokenCallback(msg.sender, _tokensReceived, _data));
        }
        return true;
    }
    
    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function getChainId() internal pure returns (uint) {
        uint256 chainId;
        assembly { chainId := chainid() }
        return chainId;
    }
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }

/**
 * @dev Hook that is called before any transfer of tokens. This includes
 * minting and burning.
 *
 * Calling conditions:
 *
 * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
 * will be to transferred to `to`.
 * - when `from` is zero, `amount` tokens will be minted for `to`.
 * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
 * - `from` and `to` are never both zero.
 *
 * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
 */