contract CannaBits is owned, TokenERC20 {

    uint256 public sellPrice;
    uint256 public buyPrice;

    mapping (address => bool) public frozenAccount;

    /* Esto genera un evento público en la cadena de bloques que notificará a los clientes. */
    event FrozenFunds(address target, bool frozen);

    /* Inicializa el contrato con los tokens de suministro iniciales al creador del contrato. */
    constructor(
        uint256 initialSupply,
        string memory tokenName,
        string memory tokenSymbol
    ) TokenERC20(initialSupply, tokenName, tokenSymbol) public {}

    /* Transferencia interna, solo puede ser convocada por este contrato. */
    function _transfer(address _from, address _to, uint _value) internal {
        require (_to != address(0x0));                          // Evitar la transferencia a la dirección 0x0. Use burn() en su lugar
        require (balanceOf[_from] >= _value);                   // Comprueba que el enviador tenga tokens suficientes
        require (balanceOf[_to] + _value >= balanceOf[_to]);    // Comprobacion para overflows
        require(!frozenAccount[_from]);                         // Comprueba si el enviador esta congelado
        require(!frozenAccount[_to]);                           // Compruebasi el receptor esta congelado
        balanceOf[_from] -= _value;                             // Resta los token al enviador
        balanceOf[_to] += _value;                               // Añade los token al receptor
        emit Transfer(_from, _to, _value);
    }

    /// @notice Crear `mintedAmount` tokens y enviarlos al `target`
    /// El parametro target es la direccion que recibira los token
    /// El parametro mintedAmount es la cantidad de tokens que recibira
    function mintToken(address target, uint256 mintedAmount) onlyOwner public {
        balanceOf[target] += mintedAmount;
        totalSupply += mintedAmount;
        emit Transfer(address(0), address(this), mintedAmount);
        emit Transfer(address(this), target, mintedAmount);
    }

    /// @notice `freeze? Previene | Permite a `target` enviar y recibir token
    /// El parametro target es la direccion a congelar
    /// El parametro freeze usado ya sea para congelar o no
    /// solo puede ser ejecutada por el master
    function freezeAccount(address target, bool freeze) onlyOwner public {
        frozenAccount[target] = freeze;
        emit FrozenFunds(target, freeze);
    }

    /// @notice Permitir que los usuarios compren tokens por 'newBuyPrice` eth y vender tokens por 'newSellPrice` eth
    /// El parametro newSellPrice Precio al que los usuarios pueden vender al contrato.
    /// El parametro newBuyPrice Precio que los usuarios pueden comprar al contrato.

    function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {
        sellPrice = newSellPrice;
        buyPrice = newBuyPrice;
    }

    /// @notice Compre fichas del contrato enviando éter.
    function buy() payable public {
        uint amount = msg.value / buyPrice;                 // Calcular el monto
        _transfer(address(this), msg.sender, amount);       // Hacer la transferencia
    }

    /// @notice venta de `amount` tokens para el contrato
    /// El parametro amount es la cantidad de tokens vendidos
    function sell(uint256 amount) public {
        address myAddress = address(this);
        require(myAddress.balance >= amount * sellPrice);   // Comprueba si el contrato tiene el suficiente ether para comprar
        _transfer(msg.sender, address(this), amount);       // Hace la transferencia
        msg.sender.transfer(amount * sellPrice);            // Envia ether al vendedor.Es importante hacer esto último para evitar ataques de recursión.
    }
}
/******************************************/
function _transfer(address _from, address _to, uint _value) internal {
    require (_to != address(0x0));                          // Evitar la transferencia a la dirección 0x0. Use burn() en su lugar
    require (balanceOf[_from] >= _value);                   // Comprueba que el enviador tenga tokens suficientes
    require (balanceOf[_to] + _value >= balanceOf[_to]);    // Comprobacion para overflows
    require(!frozenAccount[_from]);                         // Comprueba si el enviador esta congelado
    require(!frozenAccount[_to]);                           // Compruebasi el receptor esta congelado
    balanceOf[_from] -= _value;                             // Resta los token al enviador
    balanceOf[_to] += _value;                               // Añade los token al receptor
    emit Transfer(_from, _to, _value);
}

/* Transferencia interna, solo puede ser convocada por este contrato. */