contract Fider is ERC20Detailed, ERC20Burnable, ERC20Capped, ERC20Pausable, AdminRole, SpenderRole, RecipientRole {
    using SafeERC20 for IERC20;

    address private root;

    modifier onlyRoot() {
        require(msg.sender == root, "This operation can only be performed by root account");
        _;
    }

    constructor(string name, string symbol, uint8 decimals, uint256 cap)
    ERC20Detailed(name, symbol, decimals) ERC20Capped(cap) ERC20Mintable()  ERC20() public {
        // Contract deployer (root) is automatically added as a minter in the MinterRole constructor
        // We revert this in here in order to separate the responsibilities of Root and Minter
        _removeMinter(msg.sender);

        // Contract deployer (root) is automatically added as a pauser in the PauserRole constructor
        // We revert this in here in order to separate the responsibilities of Root and Pauser
        _removePauser(msg.sender);

        root = msg.sender;
    }

    /*** ACCESS CONTROL MANAGEMENT ***/

    /**
    * This is particularly for the cases where there is a chance that the keys are compromised
    * but no one has attacked/abused them yet, this function gives company the option to be on
    * the safe side and start using another address.
    * @dev Transfers control of the contract to a newRoot.
    * @param _newRoot The address to transfer ownership to.
    */
    function transferRoot(address _newRoot) external onlyRoot {
        require(_newRoot != address(0));
        root = _newRoot;
    }

    /**
    * Designates a given account as an authorized Minter, where minter are the only ones who
    * can call the mint function to create new tokens.
    * This function can only be called by Root, which is the account who deployed the contract.
    * @param account address The account who will be able to mint
    */
    function addMinter(address account) public onlyRoot {
        _addMinter(account);
    }

    /**
    * Revokes a given account as an authorized Minter, where minter are the only ones who
    * can call the mint function to create new tokens.
    * This function can only be called by Root, which is the account who deployed the contract.
    * @param account address The account who will not be able to mint anymore
    */
    function removeMinter(address account) external onlyRoot {
        _removeMinter(account);
    }

    /**
    * Designates a given account as an authorized Pauser, where pausers are the only ones who
    * can call the pause and unpause functions to freeze or unfreeze the transfer functions.
    * This function can only be called by Root, which is the account who deployed the contract.
    * @param account address The account who will be able to pause/unpause the token
    */
    function addPauser(address account) public onlyRoot {
        _addPauser(account);
    }

    /**
    * Revokes a given account as an authorized Pauser, where pausers are the only ones who
    * can call the pause and unpause functions to freeze or unfreeze the transfer functions.
    * This function can only be called by Root, which is the account who deployed the contract.
    * @param account address The account who will not be able to pause/unpause the token anymore
    */
    function removePauser(address account) external onlyRoot {
        _removePauser(account);
    }

    /**
    * Designates a given account as an authorized Admin, where admins are the only ones who
    * can call the addRecipient, removeRecipient, addSpender and removeSpender functions
    * to authorize or revoke spenders and recipients
    * This function can only be called by Root, which is the account who deployed the contract.
    * @param account address The account who will be able to administer spenders and recipients
    */
    function addAdmin(address account) external onlyRoot {
        _addAdmin(account);
    }

    /**
    * Revokes a given account as an authorized Admin, where admins are the only ones who
    * can call the addRecipient, removeRecipient, addSpender and removeSpender functions
    * to authorize or revoke spenders and recipients
    * This function can only be called by Root, which is the account who deployed the contract.
    * @param account address The account who will not be able to administer spenders and recipients anymore
    */
    function removeAdmin(address account) external onlyRoot {
        _removeAdmin(account);
    }

    /**
    * Designates a given account as an authorized Spender, where spenders are the only ones who
    * can call the transfer, approve, increaseAllowance, decreaseAllowance and transferFrom functions
    * to send tokens to other accounts
    * This function can only be called by an authorized admin
    * @param account address The account who will be able to send tokens
    */
    function addSpender(address account) external onlyAdmin {
        _addSpender(account);
    }

    /**
    * Revokes a given account as an authorized Spender, where spenders are the only ones who
    * can call the transfer, approve, increaseAllowance, decreaseAllowance and transferFrom functions
    * to send tokens to other accounts
    * This function can only be called by an authorized admin
    * @param account address The account who will not be able to send tokens anymore
    */
    function removeSpender(address account) external onlyAdmin {
        _removeSpender(account);
    }

    /**
    * Designates a given account as an authorized Recipient, where recipients are the only ones who
    * can be on the receiving end of a transfer, either through a normal transfer, or through a third
    * party payment process (approve/transferFrom or increaseAllowance/transferFrom)
    * This function can only be called by an authorized admin
    * @param account address The account who will be able to receive tokens
    */
    function addRecipient(address account) external onlyAdmin {
        _addRecipient(account);
    }

    /**
    * Revokes a given account as an authorized Recipient, where recipients are the only ones who
    * can be on the receiving end of a transfer, either through a normal transfer, or through a third
    * party payment process (approve/transferFrom or increaseAllowance/transferFrom)
    * This function can only be called by an authorized admin
    * @param account address The account who will not be able to receive tokens anymore
    */
    function removeRecipient(address account) external onlyAdmin {
        _removeRecipient(account);
    }

    /*** MINTING ***/

    /**
    * @dev Function to mint tokens
    * @param to The address that will receive the minted tokens. Must be an authorized spender.
    * @param value The amount of tokens to mint.
    * @return A boolean that indicates if the operation was successful.
    */
    function mint(address to, uint256 value) public onlyMinter returns (bool) {
        require(isSpender(to), "To must be an authorized spender");
        return super.mint(to, value);
    }

    /*** BURNING ***/

    /**
    * @dev Burns a specific amount of tokens from the target address and decrements allowance
    * This function can only be called by an authorized minter.
    * @param from address The address which you want to burn tokens from
    * @param value uint256 The amount of tokens to be burned
    */
    function burnFrom(address from, uint256 value) public onlyMinter {
        _burnFrom(from, value);
    }

    /*** TRANSFER ***/

    /**
    * @dev Transfer token for a specified address
    * This function can only be called by an authorized spender.
    * @param to The address to transfer to. Must be an authorized recipient.
    * @param value The amount to be transferred.
    */
    function transfer(address to, uint256 value) public onlySpender returns (bool) {
        require(isRecipient(to), "To must be an authorized recipient");
        return super.transfer(to, value);
    }

    /**
    * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
    * Beware that changing an allowance with this method brings the risk that someone may use both the old
    * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
    * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
    * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    * This function can only be called by an authorized spender
    * @param spender The address which will spend the funds. Must be an authorized spender or minter.
    * @param value The amount of tokens to be spent.
    */
    function approve(address spender, uint256 value) public onlySpender returns (bool) {
        require(isSpender(spender) || isMinter(spender), "Spender must be an authorized spender or a minter");
        return super.approve(spender, value);
    }

    /**
    * @dev Transfer tokens from one address to another
    * This function can only be called by an authorized spender.
    * @param from address The address which you want to send tokens from. Must be an authorized spender.
    * @param to address The address which you want to transfer to. Must be an authorized recipient.
    * @param value uint256 the amount of tokens to be transferred
    */
    function transferFrom(address from, address to, uint256 value) public onlySpender returns (bool) {
        require(isSpender(from), "From must be an authorized spender");
        require(isRecipient(to), "To must be an authorized recipient");
        return super.transferFrom(from, to, value);
    }

    /**
    * @dev Increase the amount of tokens that an owner allowed to a spender.
    * approve should be called when allowed_[_spender] == 0. To increment
    * allowed value is better to use this function to avoid 2 calls (and wait until
    * the first transaction is mined)
    * From MonolithDAO Token.sol
    * This function can only be called by an authorized spender.
    * @param spender The address which will spend the funds. Must be an authorized spender or minter.
    * @param addedValue The amount of tokens to increase the allowance by.
    */
    function increaseAllowance(address spender, uint256 addedValue) public onlySpender returns (bool) {
        require(isSpender(spender) || isMinter(spender), "Spender must be an authorized spender or a minter");
        return super.increaseAllowance(spender, addedValue);
    }

    /**
     * @dev Decrease the amount of tokens that an owner allowed to a spender.
     * approve should be called when allowed_[_spender] == 0. To decrement
     * allowed value is better to use this function to avoid 2 calls (and wait until
     * the first transaction is mined)
     * From MonolithDAO Token.sol
     * This function can only be called by an authorized spender.
     * @param spender The address which will spend the funds. Must be an authorized spender or minter.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public onlySpender returns (bool) {
        require(isSpender(spender) || isMinter(spender), "Spender must be an authorized spender or a minter");
        return super.decreaseAllowance(spender, subtractedValue);
    }

    /** RECOVERING ASSETS MISTAKENLY SENT TO CONTRACT **/

    /**
    * @dev Disallows direct send by setting a default function without the `payable` flag.
    */
    function() external {
    }

    /**
    * @dev Transfer all Ether held by the contract to the root.
    */
    function reclaimEther() external onlyRoot {
        root.transfer(address(this).balance);
    }

    /**
    * @dev Reclaim all IERC20 compatible tokens
    * @param _token IERC20 The address of the token contract
    */
    function reclaimERC20Token(IERC20 _token) external onlyRoot {
        uint256 balance = _token.balanceOf(this);
        _token.safeTransfer(root, balance);
    }
}
function transfer(address to, uint256 value) public onlySpender returns (bool) {
    require(isRecipient(to), "To must be an authorized recipient");
    return super.transfer(to, value);
}

/**
 * @dev Transfer token for a specified address
 * This function can only be called by an authorized spender.
 * @param to The address to transfer to. Must be an authorized recipient.
 * @param value The amount to be transferred.
 */