1

im in the process of learning about ethereum and Solidity, and im having a problem calling a payable function from a test file.

This is my contract

pragma solidity >=0.4.22 <0.6.0;
//pragma solidity 0.4.17

contract Lottery {

    address public manager;
    address payable [] public players;

    constructor() public {
        manager = msg.sender;
    }

    function enter() public payable {
        require(msg.value > .01 ether);
        players.push(msg.sender);
    }

    function pickWinner() public payable restricted {
        uint index = random() % players.length;
        address payable winner = players[index];
        winner.transfer(address(this).balance);
        players = new address payable [](0);
    }

    function random() private view returns (uint) {
        return uint( keccak256(abi.encode(block.difficulty, now, players)));
    }

    modifier restricted() {
        require(msg.sender == manager, 'Your are not the manager!');
        _;
    }

    function getPlayers() public view returns (address payable[] memory) {
        return players;
    }
}

and this is my test file

let lottery;
let accounts;

beforeEach(async () => {
  accounts = await web3.eth.getAccounts();
  lottery = await new web3.eth.Contract(abi)
    .deploy({data: bytecode.object})
    .send({from: accounts[0], gas: '1000000'}});
});

describe('Lottery Contract', () => {
  it('deploys contract', () => {
    assert.ok(lottery.options.address);
  });

  it('Allows 1 account to enter', async () => {
    await lottery.methods.enter().send({
      from: accounts[0],
      value: web3.utils.toWei('0.02', 'ether')
    });

    const players = await lottery.methods.getPlayers().call({
      from: accounts[0]
    });

    assert.ok(accounts[0], players[0]);
    assert.ok(1, players.length);
  });


  it('Allows multiple accounts to enter', async () => {
    let conta = 0;
    for(let account of accounts) {
      await lottery.methods.enter().send({
        from: account,
        value: web3.utils.toWei('0.02', 'ether')
      });

      const players = await lottery.methods.getPlayers().call({
        from: account
      });

      assert.equal(account, players[conta]);
      assert.equal(conta + 1, players.length);
      conta++;
    }
  });

  it('Requires a minimun ammount to enter', async () => {
    try{
      await lottery.methods.enter().send({
        from: accounts[0],
        value: 200
      });
      assert(false);
    } catch(error){
      assert(error);
    }
  });

  it('only manager can call pick winner', async () => {
    try{
      await lottery.methods.pickWinner().send({
        from: accounts[1],
      });
      assert(false);
    } catch (error) {
      console.log(error);
      assert(error);
    }
  });

  it('manager can call pick winner', async () => {
      await lottery.methods.pickWinner().send({
        from: accounts[0],
      });
      assert(true);
  });

});

No matter what I try, I'm still getting the "invalid opcode" error when calling lottery.methods.pickWinner()

This are the lib versions I'm using

 "ganache-cli": "^6.7.0",
 "mocha": "^6.2.2",
 "solc": "^0.5.14",
 "truffle-hdwallet-provider": "^1.0.17",
 "web3": "^1.2.4"

The full trace I'm getting is:

o: VM Exception while processing transaction: invalid opcode
      at Function.o.fromResults (node_modules\ganache-cli\build\ganache-core.node.cli.js:10:89727)
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:121953
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:98498
      at p (node_modules\ganache-cli\build\ganache-core.node.cli.js:25:98156)
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:98209
      at t.default (node_modules\ganache-cli\build\ganache-core.node.cli.js:37:544097)
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:99122
      at t.n.emit (node_modules\ganache-cli\build\ganache-core.node.cli.js:61:16355)
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:61:654328
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:61:654351
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:37:1093446
      at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:2:19209

Already checked Invalid Opcode opcode error Is it normal to have Invalid opcode in a contract? and VM error: invalid opcode error caused by a modifier but im pretty sure its not my case

  • 1
    Do you know which line causes the issue? You can try commenting out lines in pickWinner function. – Ismael Jan 13 at 23:09
  • great idea, I was just scratching my head on how to debug what's going on inside the contract. – Camilo Casadiego Jan 13 at 23:21
1

Your test uses a beforeEach() to set up new, blank contract to play with. That's an agreeable thing so no test is dependent on any other.

The function uses a modulo to pick a row and then forges ahead to work, but if there are players, because enter() wasn't called first, then the modulo will be zero and it will try to access row 0 in players and that doesn't exist.

You can raise a more meaningful response, but the contract is already doing the right thing.

    function pickWinner() public payable restricted {
        require(players.length > 0, "Need at least one player."); // <== this
        uint index = random() % players.length;
        address payable winner = players[index];
        winner.transfer(address(this).balance);
        players = new address payable [](0);
    }

Do a few of these before you try to pick a winner:

      await lottery.methods.enter().send({
        from: account,
        value: web3.utils.toWei('0.02', 'ether')

Hope it helps.

| improve this answer | |
  • thanks a lot, at the end of the day was an array index issue XD – Camilo Casadiego Jan 14 at 1:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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