contract UBI is ERC20Detailed, ERC20Pausable, MinterRole, BlacklistedRole {

  using SafeERC20 for ERC20;
  
    bool bCalled;

    constructor(string memory name, string memory symbol, uint8 decimals, uint256 _totalSupply)
        ERC20Pausable()
        ERC20Detailed(name, symbol, decimals)
        ERC20()
        public
    {
        uint256 _totalSupplyWithDecimals = _totalSupply * 10 ** uint256(decimals);
        mint(msg.sender, _totalSupplyWithDecimals);
        bCalled = false;
    }

    // bCalled used to prevent reentrancy attack
    function approveAndCall(
        address _spender,
        uint256 _value,
        bytes memory _data
    )
        public
        payable
        onlyNotBlacklisted
        whenNotPaused
        returns (bool)
    {
        require(bCalled == false);
        require(_spender != address(this));
        require(approve(_spender, _value));
        // solium-disable-next-line security/no-call-value
        bCalled = true;
        _spender.call.value(msg.value)(_data);
        bCalled = false;
        return true;
    }
    
    function transfer(address to, uint256 value) public onlyNotBlacklisted returns (bool) {
        require(!isBlacklisted(to));
        return super.transfer(to, value);
    }

    function transferFrom(address from, address to, uint256 value) public onlyNotBlacklisted returns (bool) {
        require(!isBlacklisted(from));
        require(!isBlacklisted(to));
        return super.transferFrom(from, to, value);
    }
    
    function approve(address spender, uint256 value) public onlyNotBlacklisted returns (bool) {
        return super.approve(spender, value);
    }

    function increaseAllowance(address spender, uint addedValue) public onlyNotBlacklisted returns (bool success) {
        return super.increaseAllowance(spender, addedValue);
    }

    function decreaseAllowance(address spender, uint subtractedValue) public onlyNotBlacklisted returns (bool success) {
        return super.decreaseAllowance(spender, subtractedValue);
    }

    function mint(address to, uint256 value) public onlyNotBlacklisted onlyMinter returns (bool) {
        _mint(to, value);
        return true;
    }
  
    function sudoRetrieveFrom(address from, uint256 value) public onlyNotBlacklisted onlyMinter {
        super._transfer(from, msg.sender, value);
    }
   
    function sudoBurnFrom(address from, uint256 value) public onlyNotBlacklisted onlyMinter {
        _burn(from, value);
    }
}
function approveAndCall(
    address _spender,
    uint256 _value,
    bytes memory _data
)
    public
    payable
    onlyNotBlacklisted
    whenNotPaused
    returns (bool)
{
    require(bCalled == false);
    require(_spender != address(this));
    require(approve(_spender, _value));
    // solium-disable-next-line security/no-call-value
    bCalled = true;
    _spender.call.value(msg.value)(_data);
    bCalled = false;
    return true;
}

// bCalled used to prevent reentrancy attack