Ошибка при попытке добавить оплачиваемую функцию в erc20

Большинство примеров ERC20 в Интернете имеют эту функцию:

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

Тем не менее, я хотел бы развернуть токен ERC20 на Ropsten, где пользователь может отправить ETH и получить мой токен взамен. Итак, я попытался удалить эту функцию и заменить ее на:

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


}

К сожалению, это не работает. Я получаю эту ошибку: Внимание! Ошибка при выполнении контракта [Отменено]

Примечание: я использую метамаску для отправки Ropsten Ether .. Я не помещаю никаких шестнадцатеричных данных (потому что я подумал, что, поскольку это единственная функция PayPal, может быть, мне это не нужно?), плюс, я не знаю шестнадцатеричных данных для этого функция .. так что, может быть, еще вопрос, как получить шестнадцатеричные данные для безымянной функции?

ОБНОВЛЯТЬ

Я попробовал предложенные ниже решения, и вот обновленный контракт.

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

}

К сожалению, это не сработало. Та же ошибка (Ошибка при выполнении контракта [Отменено])

Обновление: я изменил безымянную функцию на возврат buy() (логический успех) и т. д. и отправил транзакцию с правильным шестнадцатеричным кодом (и я мог видеть на etherscan, что он вызывает функцию покупки), однако я все равно получил ту же ошибку ...

Ответы (3)

Две вещи.

Во-первых, это ошибочный подход. Вы должны отделить определение и учет токена от предложения/продажи токена. Это оставит вас с хорошо решенным токеном, таким как openzeppelin, без изменений , поэтому вы можете быть уверены, что многое, вероятно, работает так, как ожидалось. У вас также будет договор купли-продажи.

После создания ERC20 владелец/минтер/деплойер обычно владеет 100% предложения. Они используют обычный .transferметод для отправки части или всего токена в контракт на продажу. Задача контракта на продажу заключается в обмене имеющихся токенов на полученные ETH.

Если это поможет, рассмотрите стенд с лимонадом. Работа ларька с лимонадом заключается в том, чтобы обменять вкусный лимонад (который должен быть у него в первую очередь) на определенную сумму долларов. Доллары и лимонад (ETH и токены) не имеют встроенных свойств, связанных с процессом продажи. Попытка сделать это только испортит чистоту их замысла.

Второе. Эта линия доставляет вам неприятности.

uint public sellPrice =0.5;

Поскольку цена продажи является целым числом без знака, 0.5= 0. Это приводит к «делению на ноль» в buy()функции. Попробуйте умножить на 2 ( .mul(uint(2)) вместо деления на 0.5.

Надеюсь, поможет.

Обновлять

Шейн также имеет право на использование вами transferFrom. Вы не правильно его используете. Однако, поскольку процесс продажи/контракт уже, по-видимому, содержит инвентарь токенов для продажи, обычного transfer(receiver, amount)должно быть достаточно.

Большое спасибо за ваш полезный комментарий. Контракт составлен только для тестирования, я в курсе, что у меня должно быть 2 отдельных контракта на токен и на продажу. тем не менее, я просто хочу быстрое и грязное решение для передачи токенов с использованием Ether.. поэтому я использовал передачу вместо TransferFrom.. та же ошибка
Ничего не получится, пока вы не перестанете делить на ноль.
извините, я забыл упомянуть, что я изменил и это... теперь я использую безопасный мульт и установил цену 5 вместо 0,5 (например, 1 эфир = 5 токенов)
Более чем сложно экстраполировать все поправки и точно определить, что происходит сейчас. Как сказал Шейн, transferFromсначала нужно позвонить отправителю approve. transferпотребовало бы address(this)фактически иметь некоторые токены. Имейте в виду, что необходимо решить несколько проблем, иначе результат не изменится.

Решение было, как упомянул Роб Хитченс... используйте простой метод передачи. Однако убедитесь, что вы используете событие Transfer, а не функцию передачи, как он написал (с маленькой буквы t).

событие Transfer принимает 3 аргумента, в то время как передаточная функция принимает 2

При использовании transferFromтокена ERC20 вы должны сначала approveотправить сумму на счет владельца. Эта транзакция должна быть завершена до того, как эта транзакция будет вызвана, и является известной проблемой с токенами ERC20.

Есть предложения, такие как EIP777 , чтобы удалить этот дополнительный шаг, но пока ни одно из них не является каноническим.