Я создаю токен ERC20, который будет иметь 9 отдельных раундов финансирования. Когда я вызываю функцию startNextRound в виртуальной машине JavaScript, я получаю следующую ошибку:
transact to browser/SatanCoin.sol:SatanCoin.startNextRound errored: VM error: invalid opcode.
The constructor should be payable if you send value.
The execution might have thrown.
Debug the transaction to get more information.
creation of browser/SatanCoin.sol:SatanCoin pending...
Когда я развернул тот же контракт на Rinkeby через Remix и вызвал ту же функцию, у транзакции закончился газ:
transact to browser/SatanCoin.sol:SatanCoin.startNextRound errored: Gas required exceeds limit: 3000000. An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function (that's also the reason of strong gas estimation)
Когда я использую отладчик Remix, он сообщает мне, что функция останавливается на require(msg.sender == owner);
. Что именно здесь происходит не так?
Вот код. Я наследую StandardToken от openZeplin.
contract TestCoin is StandardToken {
uint256 public rate = 0.0666 ether; //Each Testcoin will be worth .0666 ETH, Must be bought in exact increments
address public owner = msg.sender;
bool public roundActive = false; //only allows buying during a round
uint public roundNum = 0;//current round number out of 9
uint public roundMax = 74;//max number of tokens to be issued every round
uint public roundIssued;//number of tokens issued during current or previous round
address[] roundBuyers; //buyer address is recorded for every token issued
modifier onlyOwner {
require(msg.sender == owner);
_;
}
event Raffled(uint roundNumber, address winner, uint amount);
event RoundStart(uint roundNumber);
function name() constant returns (string) { return "TestCoin"; }
function symbol() constant returns (string) { return "TEST"; }
function decimals() constant returns (uint8) { return 0; }
function startNextRound()
public
{
require(msg.sender == owner);
assert(endPreviousRound()); //end the previous round before starting the next
require(roundNum<9); //only 9 rounds may occur
roundActive = true;
roundBuyers = new address[](74);
roundIssued = 0;
roundNum++;
RoundStart(roundNum);
}
function endPreviousRound()
private
returns (bool)
{
//raffles off remaining tokens if any are left
if(roundIssued < roundMax) assert(raffle(amountRemaining()));
roundActive = false;
return true;
}
//raffles off remainig tokens to a random buyer from the previous round
//the more tokens a buyer has, the greater their chance to win
function raffle(uint raffleAmount)
private
returns (bool)
{
uint randomIndex = uint(block.blockhash(block.number))%(roundMax-raffleAmount)+1;
mint(roundBuyers[randomIndex], raffleAmount);
Raffled(roundNum, roundBuyers[randomIndex], raffleAmount);
}
function mint(address receiver, uint amount)
private
{
totalSupply = safeAdd(totalSupply, amount);
balances[receiver] = safeAdd(balances[receiver], amount);
for(uint i = 0; i < amount; i++) {
roundBuyers[roundIssued+i] = receiver;
}
roundIssued = safeAdd(roundIssued, amount);
// This will make the mint transaction apper in EtherScan.io
Minted(receiver, amount);
}
//This function is called when Ether is sent to the contract address
//Even if 0 ether is sent.
function () payable {
//If value is zero or not multiple of the rate, refund user.
if (msg.value <= 0 || (msg.value % rate) != 0) revert();
uint tokenAmount = safeDiv(msg.value, rate);
//Make sure there is an active round
if(roundActive == false) revert();
//Make sure a buyer can't buy more than round amount availible.
if (tokenAmount > amountRemaining()) revert();
//Make sure that no more than 666 TestCoins can be issued.
if ((tokenAmount+totalSupply) > 666) revert();
//Extra precaution to contract attack
if (tokenAmount < 1) revert();
mint(msg.sender, tokenAmount);
owner.transfer(msg.value); //Send the ETH
}
//returns number of tokens left to be issued in current round
function amountRemaining()
public
constant
returns (uint)
{
return (roundMax-roundIssued);
}
}
Если функция не работает из-за вызовов require/assert/throw, вы получите сообщение об ошибке, связанное с нехваткой газа или неверным кодом операции vm.
Итак, если отладка показывает, что выполнение останавливается на require(msg.sender == owner); тогда единственное возможное объяснение состоит в том, что вы вызываете эту функцию с учетной записью, которая не является владельцем.
Насколько я знаю, причиной сообщения «Неверный код операции» часто является пустая переменная. Я думаю, что в вашем случае следующая строка неверна:
address public owner = msg.sender;
Говоря это
contract TestCoin is StandardToken
переменная «владелец» уже установлена конструктором StandardToken-Contract.
Поэтому, возможно, вам следует изменить строку выше на:
address public owner;
Надеюсь, поможет.
Джузеппе Бертоне