I'm creating an ERC20 token that will have 9 separate funding rounds. When I call the startNextRound function in the JavaScript VM, I get the following error:

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... 

When I deployed the same contract on Rinkeby through Remix and called the same function, the transaction ran out of gas:

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)

When I use the Remix debugger, it tells me the function is stopping at require(msg.sender == owner);. What exactly is going wrong here?

Here's the code. I'm inheriting StandardToken from openZepplin.

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


  function endPreviousRound()
    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)
    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) 

    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()
    returns (uint)
    return (roundMax-roundIssued);

  • 2
    I’m voting to close this question because the author already resolved this years ago (without specifying or knowing exactly how), and he/her never logged in more than a year now. There was an attempt by the author to advertise that but his answer was deleted (it seems his attempt have been mistaken for an incorrect answer). Jan 11 at 3:14

If the function fails due to the requires/assert/throw calls you'll get the error you are getting about running out of gas or vm invalid opcode.

So, if the debugging shows execution is stopping at require(msg.sender == owner); then the only possible explanation is that you are calling this function with an account that is not the owner.

  • That's what I thought. However, I've compared the owner variable with the account address I'm calling the function from and they're exactly the same.
    – CylonCat
    Oct 20 '17 at 23:26

As fas as I know the reason for an "Invalid Opcode" message is often a variable being empty. I think in your case the following line is not correct:

address public owner = msg.sender;

When saying that

contract TestCoin is StandardToken

the 'owner' variable gets already set by the constructor of the StandardToken-Contract.

So perhapts you should change the line above into:

address public owner;

Hope it helps.

Not the answer you're looking for? Browse other questions tagged or ask your own question.