No se puede transferir el token ERC20 de otro contrato inteligente a la persona que envía Ether

Creé dos contratos inteligentes y ambos están implementados en Ropsten Test Network. Estoy usando MetaMask para transacciones.

  1. Token ERC20 que tiene la implementación que se muestra a continuación (tenga en cuenta que puedo ver mis tokens disponibles en MetaMask):

    contract AppleToken is ERC20Interface, Owned, SafeMath {
    string public symbol;
    string public  name;
    uint8 public decimals;
    uint public _totalSupply;
    
    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;
    
    
    // ------------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------------
    function AppleToken()  public {
        symbol = "AppleToken";
        name = "Apple Token";
        decimals = 18;
        _totalSupply = 100000000000000000000000000;
        balances[0x2cBccb25319231B921fCf02Ec3bc213FcdFAeA15] = _totalSupply;
        Transfer(address(0), 0x2cBccb25319231B921fCf02Ec3bc213FcdFAeA15, _totalSupply);
    }
    
    
    // ------------------------------------------------------------------------
    // Total supply
    // ------------------------------------------------------------------------
    function totalSupply() public constant returns (uint) {
        return _totalSupply  - balances[address(0)];
    }
    
    
    // ------------------------------------------------------------------------
    // Get the token balance for account tokenOwner
    // ------------------------------------------------------------------------
    function balanceOf(address tokenOwner) public constant returns (uint balance) {
        return balances[tokenOwner];
    }
    
    
    // ------------------------------------------------------------------------
    // Transfer the balance from token owner's account to to account
    // - Owner's account must have sufficient balance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transfer(address to, uint tokens) public returns (bool success) {
        balances[msg.sender] = safeSub(balances[msg.sender], tokens);
        balances[to] = safeAdd(balances[to], tokens);
        Transfer(msg.sender, to, tokens);
        return true;
    }
    
    
    // ------------------------------------------------------------------------
    // Token owner can approve for spender to transferFrom(...) tokens
    // from the token owner's account
    //
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
    // recommends that there are no checks for the approval double-spend attack
    // as this should be implemented in user interfaces 
    // ------------------------------------------------------------------------
    function approve(address spender, uint tokens) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        Approval(msg.sender, spender, tokens);
        return true;
    }
    
    
    // ------------------------------------------------------------------------
    // Transfer tokens from the from account to the to account
    // 
    // The calling account must already have sufficient tokens approve(...)-d
    // for spending from the from account and
    // - From account must have sufficient balance to transfer
    // - Spender must have sufficient allowance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transferFrom(address from, address to, uint tokens) public returns (bool success) {
        balances[from] = safeSub(balances[from], tokens);
        allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
        balances[to] = safeAdd(balances[to], tokens);
        Transfer(from, to, tokens);
        return true;
    }
    
    
    // ------------------------------------------------------------------------
    // Returns the amount of tokens approved by the owner that can be
    // transferred to the spender's account
    // ------------------------------------------------------------------------
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining) {
        return allowed[tokenOwner][spender];
    }
    
    
    // ------------------------------------------------------------------------
    // Token owner can approve for spender to transferFrom(...) tokens
    // from the token owner's account. The spender contract function
    // receiveApproval(...) is then executed
    // ------------------------------------------------------------------------
    function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        Approval(msg.sender, spender, tokens);
        ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
        return true;
    }
    
    
    // ------------------------------------------------------------------------
    // Don't accept ETH
    // ------------------------------------------------------------------------
    function () public payable {
        revert();
    }
    
    
    // ------------------------------------------------------------------------
    // Owner can transfer out any accidentally sent ERC20 tokens
    // ------------------------------------------------------------------------
    function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
        return ERC20Interface(tokenAddress).transfer(owner, tokens);
    }
    

    }

  2. Otro contrato inteligente que recibe Ether y debería interactuar con el contrato inteligente anterior para transferir mis tokens al remitente de Ether.

Estoy tratando de implementar lo mencionado en el punto número 2, pero si trato de acceder a la función "transferir" de la instancia del token ERC20, aparece un error de estimación de gas que excede (he intentado aumentar el límite de gas, no trabajar). Además, cuando trato de forzar la transacción a través de MetaMask, me muestra el costo de ejecución como 60001 eth, incluso cuando intento enviar solo 1 éter.

Aquí está la implementación de mi función.

POR AHORA SOY EL REMITENTE DE ETER Y EL RECEPTOR DE LOS TOKENS ERC20

function sendTokens () public payable returns (uint)
    {
       //tokenAddress is the address of the ERC20 token deployed on Ropsten
        AppleToken appleToken;
        appleToken = AppleToken(tokenAddress);
        appleToken.transfer(msg.sender, 10);
        return appleToken.balanceOf(msg.sender);
    }

Estoy enviando 10 tokens codificados en este momento con fines de prueba. Tenga en cuenta que he incluido AppleToken con import "browser/AppleToken.sol";

Si ejecuto SOLAMENTE la función appleToken.balanceOf, entonces no devuelve nada. Entonces, para resumir, es problemático en la función de "transferencia" debido al costo de ejecución demasiado calculado, y no devuelve nada para "balanceOf", ni siquiera un 0.

¿Estoy iniciando la instancia de AppleToken correctamente? ¿O hay algo más que estoy haciendo mal?

Cualquier ayuda sería apreciada.

Gracias.

ACTUALIZAR

Dirección pública de la cuenta en Ropsten: 0x2cBccb25319231B921fCf02Ec3bc213FcdFAeA15

Dirección del token ERC20 en Ropsten: 0x580156edb25D3c3deD584F1075CcCC5dA4861883

A continuación se muestra el código completo del Contrato de EquityInvestments:

Eliminé cosas innecesarias en el código ya que no estoy llamando a esas funciones ni usando algunas variables definidas para el problema que estoy enfrentando.

pragma solidity ^0.4.16;
import "browser/AppleToken.sol";

contract EquityInvestments 
{
    AppleToken appleToken;
    Group [] _Groups;
    uint PriceEth = 1;
    address tokenAddress = 0x580156edb25D3c3deD584F1075CcCC5dA4861883;
    mapping (address => mapping(uint=>UserInvestment)) private _UserInvestments;

    function EquityInvestments () public
    {
        _Groups.push(Group({
            GroupID: 1,
            GroupName: "Google",
            TotalInvestment: 0,
            GroupPriceDollars: 200,
            GroupPriceEth: 1
        }));
         _Groups.push(Group({
            GroupID: 2,
            GroupName: "Tesla",
             TotalInvestment: 0,
             GroupPriceDollars: 200,
             GroupPriceEth: 1
        }));
         _Groups.push(Group({
            GroupID: 3,
            GroupName: "Apple",
             TotalInvestment: 0,
             GroupPriceDollars: 200,
             GroupPriceEth: 1
        }));
    }

    struct Group
    {
     uint GroupID;
     string GroupName;
     uint TotalInvestment;
     uint GroupPriceDollars;
     uint GroupPriceEth;
    }

    function sendTokens () public payable returns (uint)
    {
        appleToken = AppleToken(tokenAddress);
        // return appleToken.balanceOf(msg.sender);
        // appleToken.approve(this, 10);
        require(appleToken.transfer(msg.sender, 10));
        return appleToken.balanceOf(msg.sender);
    }



}

Respuestas (2)

No puedo ver qué está mal con el contrato simbólico.

En cuanto a la segunda, debe hacer:

function sendTokens () public payable returns (uint)
    {
        AppleToken appleToken = AppleToken(tokenAddress);
        require(appleToken.transfer(msg.sender, 10));
        return appleToken.balanceOf(msg.sender);
    }
  1. No es necesario declarar la variable appleToken y luego configurarla, puede combinar ambas.
  2. Asegúrate de que tokenAddresssea el correcto.
  3. ¡ Siempre use un requirecuando haga una transferencia de token! No crea que funciona como el transfermétodo para ether, que maneja fallas y arrojará por usted.

EDITAR :

He probado los contratos y funciona bien. Creo que simplemente olvidó enviar tokens al EquityInvestmentscontrato, por lo tanto, el saldo de tokens de msg.senderpermanecer en 0.

Todavía no hay suerte. Este es el error que veo, también lo estaba viendo antes. "Error en la estimación de gas con el siguiente mensaje (ver más abajo). Es probable que la ejecución de la transacción falle. ¿Desea forzar el envío? Error: el gas requerido excede la asignación o siempre falla la transacción en chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js: 18062:326 en chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:17305:855 en chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background.js:400:2363 en u (chrome- ...."
¿Puede dar todo el código + las direcciones de los contratos en ropsten?
Gracias por investigar este @Elisha, actualicé mi pregunta, verifíquelo.
@MuradHasan ¿Realmente acreditó el contrato de EquityInvestments con tokens?
@ElishaDion, ¿podría dar más detalles? Porque no estoy tratando de enviar tokens al contrato de EquityInvestments. Este contrato es solo para aceptar Ether y debe llamar a la función de transferencia del contrato AppleToken para enviar tokens a la dirección de msg.sender (que se recibió en el contrato EquityInvestments)
Deberías leer cómo transferfunciona. Se "da" una cierta cantidad del msg.sender, el que llama a la función, a otra dirección. Si su contrato no tiene tokens, no puede enviar nada a las personas que etherle envían. En su caso, no puede acuñar mágicamente nuevos tokens.
¡Usted, señorita, me ha salvado el día! Entendí el concepto MUCHO mejor ahora. Funcionó. ¡Gracias! @ElishaDrion

Para profundizar en un comentario de @elidrion, el .transfermétodo adjunto a los contratos ENVIARÁ ETHER NO TOKENS desde el mensaje del contrato al propietario.

Por ejemplo, para extraer tokens de un contrato, no use el método de transferencia global proporcionado por Solidity, haga algo como esto:

function transferTokensOutOfTokenContract(uint tokens) public onlyOwner returns (bool success) {
        require(tokens <= balances[address(this)]);
        balances[address(this)] = balances[address(this)].sub(tokens);
        balances[msg.sender] = balances[msg.sender].add(tokens);
        emit Transfer(address(this), msg.sender, tokens);
        return true;
    }