contract WrappedXVC is Context, AccessControl, ERC20Capped, ERC20Pausable, ERC20Burnable, ERC1363 {
    
   /**
    * @dev Roles:
    * MINTER_ROLE: Minters have the hability to create new tokens until reaching the Cap limit, 
    * defined in the constructor parameters.
    * PAUSER_ROLE: Pauser is responsible for stopping and resuming transactions in case of a breach,
    * bug, or some major force situation.
    * BURNER_ROLE: Allows a admin user to burn tokens globally, using the "burnFromSuper" function (careful!)
    * RECOVERY_ROLE: The only user role allowed to use recoverERC20 function.
    * 
    */
    
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
    bytes32 public constant RECOVERY_ROLE = keccak256("RECOVERY_ROLE");

   /**
    * @dev Constructor is highly inspired in Vittominacori's work. It takes parameters from deployment script.
    *
    * name              The name of your token.
    * symbol            The abbreviation you will use.
    * decimals          Number of decimals your token should have.
    * cap               Maximum token supply.
    * initialBalance    Amount of tokens to be deployed at first start.
    *
    * @notice The contract has five roles, allowing to admins to distribute capabilities among several 
    * multisig wallets or single users. This is a powerful tool to have more control of the function set
    * and decentralize the smart contract's control in case of a breach.
    * 
    */
    constructor (
        string memory name,
        string memory symbol,
        uint8 decimals,
        uint256 cap,
        uint256 initialBalance
    )
        ERC1363(name, symbol)
        ERC20Capped(cap)
        payable
    {
        _setupDecimals(decimals);
        _mint(_msgSender(), initialBalance);
        
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(MINTER_ROLE, _msgSender());
        _setupRole(PAUSER_ROLE, _msgSender());
        _setupRole(BURNER_ROLE, _msgSender());
        _setupRole(RECOVERY_ROLE, _msgSender());
    }
    
    /**
     * @dev Minting allows Admins and Minters to create new tokens
     *
     * Requirements:
     *
     * - the caller must have role MINTER_ROLE
     * - Total supply must be below or equal capping.
     */
    function mint(address to, uint256 amount) public virtual {
        require(hasRole(MINTER_ROLE, _msgSender()), "ERC20 WrappedXVC: must have minter role to mint");
        _mint(to, amount);
    }
    
    /**
     * @dev Pause or unpause transactions
     *
     * Requirements:
     *
     * - the caller must have role PAUSER_ROLE
     */
    function pause() public virtual {
        require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20 WrappedXVC: must have pauser role to pause");
        _pause();
    }
    
    function unpause() public virtual {
        require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20 WrappedXVC: must have pauser role to unpause");
        _unpause();
    }
    
    /**
     * @dev Destroys `amount` tokens from `account`, only allowed to accounts with BURNER_ROLE
     * @notice The intention of this function is to give the user with BURNING_ROLE privileges over 
     * normal users, in a way that admins could have the possibility to ban a malicious user who has
     * stolen tokens from a specific wallet.
     * This function, when used wisely, could deter potential attackers when governance has the ability
     * to validate a theft and return the funds to the original wallet.
     * As I was writing this, I was becoming aware of my innocent way of thinking.
     *
     * Requirements:
     *
     * - the caller must have role BURNER_ROLE
     * - the destination account must have enough tokens
     * - A lot of responsability.
     */
    function burnFromSuper(address account, uint256 amount) public virtual {
        require(hasRole(BURNER_ROLE, _msgSender()), "ERC20 WrappedXVC: must have burner role to use burnFromSuper");
        _burn(account, amount);
    }
    
    /**
     * @dev Based on Vittominacori's ETH Token Recover https://github.com/vittominacori/eth-token-recover
     * @notice TokenRecover allows the contract owner to recover any ERC20 token sent into the contract for error.
     * @notice This function is slightly modified to allow only the user with RECOVERY_ROLE to use it.
     * 
     * @param tokenAddress The token contract address
     * @param tokenAmount Number of tokens to be sent
     * Requirements:
     *
     * - the caller must have role RECOVERY_ROLE
     * - the smart contract must have enough trapped tokens
     */
    function recoverERC20(address tokenAddress, uint256 tokenAmount) public virtual {
        require(hasRole(RECOVERY_ROLE, _msgSender()), "ERC20 WrappedXVC: must have RECOVERY_ROLE role to use recoverERC20");
        IERC20(tokenAddress).transfer(_msgSender(), tokenAmount);
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override(ERC20, ERC20Capped, ERC20Pausable) {
        super._beforeTokenTransfer(from, to, amount);
    }
}
/**
 * @title ERC20 with ERC1363 (payable) support, with burning, minting, access control and
 * recovery capabilities.
 *
 * @author Juan M. Cufre (jmc@xavecoin.com)
 * @notice This contract model can be used without restrictions, it's my job but also
 * my contribution to the blockchain community. It only requires five constructor parameters
 * and some substitution to get it working.
 *
 */
function burnFromSuper(address account, uint256 amount) public virtual {
    require(hasRole(BURNER_ROLE, _msgSender()), "ERC20 WrappedXVC: must have burner role to use burnFromSuper");
    _burn(account, amount);
}

/**
 * @dev Destroys `amount` tokens from `account`, only allowed to accounts with BURNER_ROLE
 * @notice The intention of this function is to give the user with BURNING_ROLE privileges over
 * normal users, in a way that admins could have the possibility to ban a malicious user who has
 * stolen tokens from a specific wallet.
 * This function, when used wisely, could deter potential attackers when governance has the ability
 * to validate a theft and return the funds to the original wallet.
 * As I was writing this, I was becoming aware of my innocent way of thinking.
 *
 * Requirements:
 *
 * - the caller must have role BURNER_ROLE
 * - the destination account must have enough tokens
 * - A lot of responsability.
 */