Error al intentar agregar una función de pago en erc20

La mayoría de los ejemplos de ERC20 en Internet tienen esta función:

// ------------------------------------------------------------------------
// Don't accept ETH
// ------------------------------------------------------------------------
function () public payable {
    revert();
}

Sin embargo, me gustaría implementar un token ERC20 en Ropsten donde un usuario puede enviar ETH y recibir mi token a cambio. Entonces, lo que he intentado es eliminar esta función y reemplazarla con:

uint public sellPrice =0.5;


function setPrices(uint newSellPrice) public onlyOwner {
    sellPrice = newSellPrice;
}


function buy(uint256 payload) public payable {
    uint amount = safeDiv(msg.value, sellPrice);               
   //balances[msg.sender] += amount; //I commented this out cuz im not sure if I need it

    transferFrom(owner, msg.sender, amount);


}

Lamentablemente, esto no funciona. Recibo este error: ¡Advertencia! Error encontrado durante la ejecución del contrato [Revertido]

Nota: estoy usando metamask para enviar el Ropsten Ether. No estoy poniendo ningún dato hexadecimal (porque pensé que, dado que esta es la única función de PayPal, ¿quizás no la necesito?) Además, no conozco los datos hexadecimales para esto. función ... así que tal vez otra pregunta, ¿cómo obtener datos hexadecimales para una función sin nombre?

ACTUALIZAR

Probé las soluciones sugeridas a continuación, y aquí está el contrato actualizado

epragma solidity ^0.4.20;



 contract SafeMath {
function safeAdd(uint a, uint b) public pure returns (uint c) {
    c = a + b;
    require(c >= a);
}
function safeSub(uint a, uint b) public pure returns (uint c) {
    require(b <= a);
    c = a - b;
}
function safeMul(uint a, uint b) public pure returns (uint c) {
    c = a * b;
    require(a == 0 || c / a == b);
}
function safeDiv(uint a, uint b) public pure returns (uint c) {
    require(b > 0);
    c = a / b;
}

}

  contract ERC20Interface {
function totalSupply() public view returns (uint);
function balanceOf(address tokenOwner) public view returns (uint balance);
function allowance(address tokenOwner, address spender) public view returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);

event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

}

 contract ApproveAndCallFallBack {
function receiveApproval(address from, uint256 tokens, address token, bytes data) public;

}

 contract Owned {
address public owner;
address public newOwner;

event OwnershipTransferred(address indexed _from, address indexed _to);

function Owned() public {
    owner = msg.sender;
}

modifier onlyOwner {
    require(msg.sender == owner);
    _;
}

function transferOwnership(address _newOwner) public onlyOwner {
    newOwner = _newOwner;
}
function acceptOwnership() public {
    require(msg.sender == newOwner);
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
    newOwner = address(0);
}

}

 contract FToken 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;


function FToken() public {
    symbol = "fff";
    name = "FAdi Token";
    decimals = 18;
    _totalSupply = 1000000000;

    balances[owner] = _totalSupply;
    Transfer(address(0), owner, _totalSupply);
}


function totalSupply() public view returns (uint) {
    return _totalSupply - balances[address(0)];
}



function balanceOf(address tokenOwner) public view returns (uint balance) {
    return balances[tokenOwner];
}



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;
}



function approve(address spender, uint tokens) public returns (bool success) {
    allowed[msg.sender][spender] = tokens;
    Approval(msg.sender, spender, tokens);
    return true;
}


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;
}

function allowance(address tokenOwner, address spender) public constant returns (uint remaining) {
    return allowed[tokenOwner][spender];
}



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;
}


uint public sellPrice =5;


function setPrices(uint newSellPrice) public onlyOwner {
    sellPrice = newSellPrice;
}


function buy() public payable returns (bool success) {

    uint amount = safeMul(msg.value, sellPrice);              // calculates the amount

    //balances[msg.sender] += amount;
    if (approve(owner, amount))

    transferFrom( owner,msg.sender, amount);


}


function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
    return ERC20Interface(tokenAddress).transfer(owner, tokens);
}

}

Lamentablemente no funcionó... Mismo error (Error encontrado durante la ejecución del contrato [Revertido])

Actualización: he cambiado la función sin nombre para comprar () devuelve (éxito bool) ... etc. y envié una transacción con el hexadecimal correcto (y pude ver en etherscan que llamó a la función de compra), sin embargo, todavía recibí el mismo error...

Respuestas (3)

Dos cosas.

En primer lugar, este es un enfoque equivocado. Debe separar la definición y contabilidad de un token de la oferta/venta del token. Esto lo dejará con un token bien resuelto, como openzeppelin, sin cambios, por lo que puede estar seguro de que probablemente funcione como se esperaba. También tendrá un contrato de Venta.

Después de que se crea el ERC20, el propietario/minter/implementador normalmente posee el 100% del suministro. Usan un .transfermétodo regular para enviar parte o la totalidad del token al contrato de Venta. El trabajo del contrato de venta es intercambiar tokens disponibles por ETH recibido.

En caso de que ayude, considere un puesto de limonada. El trabajo del puesto de limonada es intercambiar una deliciosa limonada (que debe tener en primer lugar) por una cierta cantidad de dólares. Los dólares y la limonada (ETH y tokens) no tienen propiedades incorporadas relacionadas con el proceso de venta. Intentar hacerlo solo adulteraría la pureza de su diseño.

Segunda cosa. Esta línea te mete en problemas.

uint public sellPrice =0.5;

Dado que el precio de venta es un número entero sin signo, 0.5= 0. Esto lleva a "dividir por cero" en la buy()función. Considere multiplicar por 2 ( .mul(uint(2)) en lugar de dividir por 0.5.

Espero eso ayude.

Actualizar

Shane también tiene razón con tu uso de transferFrom. No lo estás usando correctamente. Sin embargo, dado que el proceso/contrato de venta ya tendrá, presumiblemente, un inventario de fichas para vender, una regular transfer(receiver, amount)debería ser suficiente.

Muchas gracias por tu útil comentario. El contrato se hace solo para probar, soy consciente de que debería tener 2 contratos separados para token y venta. sin embargo, solo quiero una solución rápida y sucia para transferir tokens usando Ether... así que usé transfer en lugar de transferFrom... mismo error
Nada funcionará hasta que dejes de dividir por cero.
lo siento, olvidé mencionar que también cambié eso... ahora uso mult seguro, y establecí el precio en 5 en lugar de 0.5 (como 1 ether = 5 tokens)
Es más que un poco difícil extrapolar de todas las correcciones y precisar lo que está sucediendo ahora. Como dijo Shane, transferFromrequiere que el remitente llame primero approve. transferrequeriría address(this)en realidad tiene algunos tokens. Tenga en cuenta que hay varios problemas que resolver o el resultado no cambiará.

La solución fue, como mencionó Rob Hitchens ... usar un método de transferencia simple. Sin embargo, asegúrese de usar el evento Transferencia, no la función de transferencia como lo escribió (con t minúscula).

el evento Transfer toma 3 argumentos, mientras que la función de transferencia toma 2

Cuando se usa transferFromen un token ERC20, primero debe approvela cantidad a enviar en la cuenta del propietario. Esta transacción debe completarse antes de que se llame a esta transacción, y es un punto problemático conocido con los tokens ERC20.

Hay sugerencias como EIP777 para eliminar este paso adicional, pero ninguna es canónica hasta el momento.