No se puede interactuar con el contrato de Crowdsale

Estoy probando un contrato Crowdsale (C) que envía tokens de un contrato ya implementado (T). La idea es enviar una cantidad de tokens a C desde T, y luego venderlos por Ether, pero nada funciona, C ni siquiera recibe el Ether. Aquí está el contrato de Crowdsale:

pragma solidity ^0.4.13;

contract ForeignToken {
    function balanceOf(address _owner) constant returns (uint256);
    function transfer(address _to, uint256 _value) returns (bool);
}

library SafeMath {
  function mul(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a / b;
    return c;
  }

  function sub(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

contract Token { 
    function issue(address _recipient, uint256 _value) returns (bool success);
    function totalSupply() constant returns (uint256 supply);
    function unlock() returns (bool success);
}

contract TokenCrowdsale {

    using SafeMath for uint256;

    // Crowdsale details
    address public beneficiary;                     
    address public creator;                         
    address public confirmedBy;                     
    uint256 public maxSupply = 15000000e8;    
    uint256 public minAcceptedAmount = 10 finney;   
    bool public purchasingAllowed = false;


    // Eth to token rate
    uint256 public rate = 2000;

    enum Stages {
        PreSale,
        InProgress,
        Ended,
        Withdrawn
    }

    Stages public stage = Stages.PreSale;

    // deployed token
    Token public deplToken;

    // Invested balances
    mapping (address => uint256) balances;

    /**
    * Throw if at stage other than current stage
    * 
    * @param _stage expected stage to test for
    */
    modifier atStage(Stages _stage) {
        require(stage == _stage);
        _;
    }

    /**
    * Throw if sender is not beneficiary
    */
    modifier onlyBeneficiary() {
        require(beneficiary == msg.sender);
        _;
    }

    /** 
    * Get balance of `_investor` 
    * 
    * @param _investor The address from which the balance will be retrieved
    * @return The balance
    */
    function balanceOf(address _investor) constant returns (uint256 balance) {
        return balances[_investor];
    }


    function enablePurchasing() onlyBeneficiary atStage(Stages.PreSale) {
        purchasingAllowed = true;
        stage = Stages.InProgress;
    }

    function disablePurchasing() onlyBeneficiary atStage(Stages.InProgress) {
        purchasingAllowed = false;
        stage = Stages.Ended;
    }

    function enableNewPurchasing() onlyBeneficiary atStage(Stages.Withdrawn) {
        purchasingAllowed = true;
        stage = Stages.InProgress;
    }

    /**
    * Constructor
    *
    * @param _tokenAddress The address of the token contact
    * @param _beneficiary  The address of the wallet for the beneficiary  
    * @param _creator      The address of the wallet for the creator 
    */
    function TokenCrowdsale(address _tokenAddress, address _beneficiary, address _creator) {
        deplToken = Token(_tokenAddress);
        beneficiary = _beneficiary;
        creator = _creator;
    }

    /**
    * For testing purposes
    *
    * @return The beneficiary address
    */
    function confirmBeneficiary() onlyBeneficiary {
        confirmedBy = msg.sender;
    }


    /**
    * Transfer raised amount to the beneficiary address
    */
    function withdraw() onlyBeneficiary atStage(Stages.Ended) {
        uint256 ethBalance = this.balance;
        beneficiary.transfer(ethBalance);
        stage = Stages.Withdrawn;
    }

    /**
    * Receives Eth and issue tokens to the sender
    */
    function () payable atStage(Stages.InProgress) {

        require(purchasingAllowed);

        address investor = msg.sender;
        uint256 received = (msg.value).div(10e8);

        // Enforce min amount
        require(received >= minAcceptedAmount);
        uint256 tokens = (received).mul(rate);

        require(tokens > 0);

        require(deplToken.issue(investor, tokens));

        balances[investor] = balances[investor].add(received);
        //raised += received;

        // Check totalSupply raised
        if (deplToken.totalSupply() >= maxSupply) {
            stage = Stages.Ended;
        }
    }

    function withdrawForeignTokens(address _tokenContract) onlyBeneficiary public returns (bool) {
        ForeignToken token = ForeignToken(_tokenContract);
        uint256 amount = token.balanceOf(address(this));
        return token.transfer(beneficiary, amount);
    }
}

Cualquier ayuda se agradece, gracias

EDITAR: después de las sugerencias en los comentarios, logré recibir ETH en el contrato de Crowdsale, pero no está emitiendo los tokens. Aquí está el código:

pragma solidity ^0.4.13;

contract ForeignToken {
    function balanceOf(address _owner) constant returns (uint256);
    function transfer(address _to, uint256 _value) returns (bool);
}

library SafeMath {
  function mul(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a / b;
    return c;
  }

  function sub(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

contract Token { 
    function issue(address _recipient, uint256 _value) returns (bool success);
    function totalSupply() constant returns (uint256 supply);
    function unlock() returns (bool success);
}

contract TokenCrowdsale {

    using SafeMath for uint256;

    // Crowdsale details
    address public beneficiary;                     
    address public creator;                         
    address public confirmedBy;                     
    uint256 public maxSupply = 15000000e8;    
    uint256 public minAcceptedAmount = 10 finney;
    bool public purchasingAllowed = false;
    uint256 public totalSupply = 0;

    // Eth to token rate
    uint256 public rate = 2000;

    enum Stages {
        PreSale,
        InProgress,
        Ended,
        Withdrawn
    }

    Stages public stage = Stages.PreSale;

    // deployed token
    Token public deplToken;

    // Invested balances
    mapping (address => uint256) balances;

    /**
    * Throw if at stage other than current stage
    * 
    * @param _stage expected stage to test for
    */
    modifier atStage(Stages _stage) {
        require(stage == _stage);
        _;
    }

    /**
    * Throw if sender is not beneficiary
    */
    modifier onlyBeneficiary() {
        require(beneficiary == msg.sender);
        _;
    }

    /** 
    * Get balance of `_investor` 
    * 
    * @param _investor The address from which the balance will be retrieved
    * @return The balance
    */
    function balanceOf(address _investor) constant returns (uint256 balance) {
        return balances[_investor];
    }


    function enablePurchasing() onlyBeneficiary atStage(Stages.PreSale) {
        purchasingAllowed = true;
        stage = Stages.InProgress;
    }

    function disablePurchasing() onlyBeneficiary atStage(Stages.InProgress) {
        purchasingAllowed = false;
        stage = Stages.Ended;
    }

    function enableNewPurchasing() onlyBeneficiary atStage(Stages.Withdrawn) {
        purchasingAllowed = true;
        stage = Stages.InProgress;
    }

    /**
    * Constructor
    *
    * @param _tokenAddress The address of the token contact
    * @param _beneficiary  The address of the wallet for the beneficiary  
    * @param _creator      The address of the wallet for the creator 
    */
    function TokenCrowdsale(address _tokenAddress, address _beneficiary, address _creator) {
        deplToken = Token(_tokenAddress);
        beneficiary = _beneficiary;
        creator = _creator;
    }

    /**
    * For testing purposes
    *
    * @return The beneficiary address
    */
    function confirmBeneficiary() onlyBeneficiary {
        confirmedBy = msg.sender;
    }


    /**
    * Transfer raised amount to the beneficiary address
    */
    function withdraw() onlyBeneficiary atStage(Stages.Ended) {
        uint256 ethBalance = this.balance;
        beneficiary.transfer(ethBalance);
        stage = Stages.Withdrawn;
    }

    /**
    * Receives Eth and issue tokens to the sender
    */
    function () payable atStage(Stages.InProgress) {
        require(purchasingAllowed);

        if (msg.value >= 10 finney) {
            address investor = msg.sender;
            uint256 received = (msg.value).div(10e8);
            uint256 tokens = (received).mul(rate);
            balances[investor] = balances[investor].add(tokens);
            totalSupply = (totalSupply).add(tokens);
        }

        if (totalSupply >= maxSupply) {
            purchasingAllowed = false;
            stage = Stages.Ended;
        }

    }

    function withdrawForeignTokens(address _tokenContract) onlyBeneficiary public returns (bool) {
        ForeignToken token = ForeignToken(_tokenContract);
        uint256 amount = token.balanceOf(address(this));
        return token.transfer(beneficiary, amount);
    }
}

Como puede ver, cambié el "requerir" en la función alternativa con una iteración "si"

¿Puede dar más detalles sobre "lo que no funciona"? ¿Puedes mostrarnos cómo llamas a las funciones? con web3? ¿Con tu billetera?
@AlxMrx parece que tu código está funcionando... ¿Lo intentaste usando Mist?
Bueno, lo implementé en testnet (Rinkeby) con Mist, luego le envié 15 millones de tokens y lancé la función "habilitar compra"; pero si trato de enviar ETH desde otra billetera, no pasa nada, la transacción devuelve un estado de "Falla"
tienes un fallo: fuddTokenno existe
Sí, lo siento, es correcto en el contrato implementado deplToken, ya que pegué aquí un código antiguo. corregido ahora
ACTUALIZACIÓN: Traté de deshabilitar la compra, retirar (saldo 0, por supuesto, pero solo para seguir el flujo de ventas del contrato) y habilitar una nueva compra, pero aún no funciona, todas las transacciones del contrato fallan
OK. Estoy tratando de reproducir el error aquí. Y noté que estás usando la función de respaldo. Debes evitarlo. Palabras de Vitalik
¿Está implementando un contrato de token? ¿Es correcta la dirección que usa dentro del contrato de TokenCrowdsale? Me está funcionando aquí. Usé Remix e implementé contratos usando cuentas de VM de Javascript. Intente eliminar todas las líneas dentro de la función de reserva y llámela. Una transacción debe funcionar y no lanzar/revertir. Luego agrega línea por línea y ve a dónde se está revirtiendo. Espero que ayude.
El contrato de token ya está implementado y la dirección en los constructores de Crowdsale es correcta (puedo ver correctamente el contrato de token en el contrato de Crowdsale en Mist). ¿Puedes publicar el código de tu función alternativa? Siempre me devuelve fallado también en VM. aunque muchas gracias por tu ayuda
Ok, ahora logré recibir el Ether en el contrato de Crowdsale, pero no está emitiendo los tokens. Editaré mi OP con el nuevo código.

Respuestas (1)

Seguir las sugerencias e investigar más me llevó a encontrar la solución. Primero cambié el

contract Token {}

a

interface Token {}

También agregué un evento que luego llama la función de respaldo para enviar tokens:

event sendTokens(address indexed to, uint256 value);

Finalmente, limpié el código de variable no utilizada y agregué alguna otra función no relacionada con mi problema, pero útil para administrar el crowdsale. Aquí está el código de trabajo final:

pragma solidity ^0.4.13;

contract ForeignToken {
    function balanceOf(address _owner) constant returns (uint256);
    function transfer(address _to, uint256 _value) returns (bool);
}

library SafeMath {
  function mul(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a / b;
    return c;
  }

  function sub(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

interface Token { 
    function transfer(address _to, uint256 _value) returns (bool);
    function totalSupply() constant returns (uint256 supply);
    function balanceOf(address _owner) constant returns (uint256 balance);
}

contract TokenCrowdsale {

    using SafeMath for uint256;

    // Crowdsale details
    address public beneficiary;                     
    address public creator;                         
    address public confirmedBy;                     
    uint256 public maxSupply = 15000000e8;    
    bool public purchasingAllowed = false;
    uint256 public totalSupplied = 0;

    // Eth to token rate
    uint256 public rate = 2000;

    enum Stages {
        PreSale, //0
        InProgress, //1
        Ended, //2 
        Withdrawn //3
    }

    Stages public stage = Stages.PreSale;

    // deployed token
    Token public deplToken;

    // Invested balances
    mapping (address => uint256) balances;

    /**
    * Throw if at stage other than current stage
    * 
    * @param _stage expected stage to test for
    */
    modifier atStage(Stages _stage) {
        require(stage == _stage);
        _;
    }

    /**
    * Throw if sender is not beneficiary
    */
    modifier onlyBeneficiary() {
        require(beneficiary == msg.sender);
        _;
    }

    /** 
    * Get balance of `_investor` 
    * 
    * @param _investor The address from which the balance will be retrieved
    * @return The balance
    */
    function balanceOf(address _investor) constant returns (uint256 balance) {
        return balances[_investor];
    }


    function enablePurchasing() onlyBeneficiary atStage(Stages.PreSale) {
        purchasingAllowed = true;
        stage = Stages.InProgress;
    }

    function disablePurchasing() onlyBeneficiary atStage(Stages.InProgress) {
        purchasingAllowed = false;
        stage = Stages.Ended;
    }

    function enableNewPurchasing() onlyBeneficiary atStage(Stages.Withdrawn) {
        purchasingAllowed = true;
        stage = Stages.InProgress;
    }

    /**
    * Constructor
    *
    * @param _tokenAddress The address of the token contact
    * @param _beneficiary  The address of the wallet for the beneficiary  
    * @param _creator      The address of the wallet for the creator 
    */
    function TokenCrowdsale(address _tokenAddress, address _beneficiary, address _creator) {
        deplToken = Token(_tokenAddress);
        beneficiary = _beneficiary;
        creator = _creator;
    }

    /**
    * For testing purposes
    *
    * @return The beneficiary address
    */
    function confirmBeneficiary() onlyBeneficiary {
        confirmedBy = msg.sender;
    }


    event sendTokens(address indexed to, uint256 value);


    /**
    * Transfer raised amount to the beneficiary address
    */
    function withdraw() onlyBeneficiary atStage(Stages.Ended) {
        uint256 ethBalance = this.balance;
        beneficiary.transfer(ethBalance);
        stage = Stages.Withdrawn;
    }

    /**
    * Receives Eth and issue tokens to the sender
    */
    function () payable atStage(Stages.InProgress) {

        require(purchasingAllowed);
        if (msg.value == 0) { return; }
        uint256 weiAmount = msg.value;
        address investor = msg.sender;
        uint256 received = weiAmount.div(10e7);
        uint256 tokens = (received).mul(rate);

        if (msg.value >= 10 finney) {
            uint256 bonusToken = (tokens.div(100)).mul(20);
            tokens = tokens.add(bonusToken);
        }

        sendTokens(msg.sender, tokens);
        deplToken.transfer(investor, tokens);
        totalSupplied = (totalSupplied).add(tokens);

        if (totalSupplied >= maxSupply) {
            purchasingAllowed = false;
            stage = Stages.Ended;
        }

    }


    function tokensAvailable() constant returns (uint256) {
        return deplToken.balanceOf(this);
    }


    function withdrawForeignTokens(address _tokenContract) onlyBeneficiary public returns (bool) {
        ForeignToken token = ForeignToken(_tokenContract);
        uint256 amount = token.balanceOf(address(this));
        return token.transfer(beneficiary, amount);
    }
}

No estoy seguro de si "token de interfaz" o "tokens de envío de eventos", o ambos juntos, fueron las soluciones, pero ahora está funcionando; Puedo enviar ether y recibir el token desplegado. Respondí mi propia pregunta, por lo que permanecerá aquí como una solución si alguien más necesita algo como esto. Gracias