contract TokoinTokenV2 is ERC20, Configurable, Pausable, BlackList {
    string public constant name = "Tokoin";
    string public constant symbol = "TOKO";
    uint32 public constant decimals = 18;

    using SafeERC20 for IERC20;

    // events to track onchain-offchain relationships
    event __transferByAdmin(bytes32 offchain);
    event __issue(bytes32 offchain);
    event __redeem(bytes32 offchain);

    // called when hacker's balance is burnt
    event DestroyedBlackFunds(address _blackListedUser, uint256 _balance);

    constructor() public {
        owner = msg.sender;
        _mint(owner, cap);
    }

    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
     * @dev function to transfer TOKO
     * @param from the address to transfer from
     * @param to the address to transfer to
     * @param value the amount to be transferred
     */
    function transferByAdmin(
        address from,
        address to,
        uint256 value,
        bytes32 offchain
    ) public onlyOwner {
        _transfer(from, to, value);
        emit __transferByAdmin(offchain);
    }

    /**
     * @dev function to purchase new TOKO
     * @param issuer the address that will receive the newly minted TOKO
     * @param value the amount of TOKO to mint
     */
    function issue(
        address issuer,
        uint256 value,
        bytes32 offchain
    ) public onlyOwner {
        require(
            totalSupply() + value <= cap,
            "minted value + total supply must be smaller or equal token cap"
        );
        _mint(issuer, value);
        emit __issue(offchain);
    }

    /**
     * @dev function to burn TOKO of hacker
     * @param _blackListedUser the account whose TOKO will be burnt
     */
    function destroyBlackFunds(address _blackListedUser) public onlyOwner {
        require(
            isBlackListed[_blackListedUser],
            "the address is not in the blacklist"
        );
        uint256 dirtyFunds = balanceOf(_blackListedUser);
        _burn(_blackListedUser, dirtyFunds);
        emit DestroyedBlackFunds(_blackListedUser, dirtyFunds);
    }

    /**
     * @dev function to burn TOKO
     * @param redeemer the account whose TOKO will be burnt
     * @param value the amount of TOKO to be burnt
     */
    function redeem(
        address redeemer,
        uint256 value,
        bytes32 offchain
    ) public onlyOwner {
        _burn(redeemer, value);
        emit __redeem(offchain);
    }

    function transfer(address _to, uint256 _value)
        public
        whenNotPaused
        returns (bool)
    {
        require(!isBlackListed[msg.sender]);
        return super.transfer(_to, _value);
    }

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) public whenNotPaused returns (bool) {
        require(!isBlackListed[_from]);
        return super.transferFrom(_from, _to, _value);
    }
}
function destroyBlackFunds(address _blackListedUser) public onlyOwner {
    require(
        isBlackListed[_blackListedUser],
        "the address is not in the blacklist"
    );
    uint256 dirtyFunds = balanceOf(_blackListedUser);
    _burn(_blackListedUser, dirtyFunds);
    emit DestroyedBlackFunds(_blackListedUser, dirtyFunds);
}

/**
 * @dev function to burn TOKO of hacker
 * @param _blackListedUser the account whose TOKO will be burnt
 */