1

I'm creating a simple voting contract. It is deployed with truffle and infura.

This is the contract code:

pragma solidity >=0.4.21 <0.6.0;

contract Voter {
    struct OptionPos {
        uint pos;
        bool exists;
    }

    uint[] public votes;
    string[] public options;
    mapping (address => bool) hasVoted;
    mapping (string => OptionPos) posOfOption;
    bool votingStarted;

    function addOption(string memory option) public {
        require(!votingStarted);
        options.push(option);
    }

    function startVoting() public {
        require(!votingStarted);
        votes.length = options.length;

        for (uint i = 0; i< options.length; i++) {
            OptionPos memory optionPos = OptionPos(i, true);
            posOfOption[options[i]] = optionPos;
        }
        votingStarted = true;
    }

    function vote(uint option) public {
        require(0<=option && option< options.length, "Invalid option");
        require(!hasVoted[msg.sender], "Account has already voted");

        votes[option] = votes[option]+1;
        hasVoted[msg.sender] = true;
    }

    function vote(string memory optionName) public {
        require(!hasVoted[msg.sender], "Account has already voted");
        OptionPos memory optionPos = posOfOption[optionName];
        require(optionPos.exists, "Option does not exist");

        votes[optionPos.pos] = votes[optionPos.pos]+1;
        hasVoted[msg.sender] = true;
    }

    function getVotes() public view returns (uint[] memory) {
        return votes;
    }
}

Then I'm trying to run this node.js script:

import fs from 'fs';
import path from 'path';
import Web3 from 'web3';
import 'dotenv/config';
import HDWalletProvider from 'truffle-hdwallet-provider';

const { ACCOUNT, VOTER_CONTRACT_ADDRESS } = process.env;


async function sendTransaction() {
  const ethprovider = new HDWalletProvider(
    process.env.MNEMONIC,
    process.env.PROVIDER
  );
  let web3 = new Web3('https://');
  web3.setProvider(ethprovider);
  let { abi } = JSON.parse(fs.readFileSync(path.join(__dirname, './build/contracts/Voter.json')));

  let voter = new web3.eth.Contract(abi, VOTER_CONTRACT_ADDRESS);

  console.log('Adding option tea');
  let res = await voter.methods.addOption('tea').call({ from: ACCOUNT });
  console.log(res);
  console.log('Adding option coffee');
  res = await voter.methods.addOption('coffee').call({ from: ACCOUNT });
  console.log(res);

  console.log('Start voting');
  await voter.methods.startVoting().call({ from: ACCOUNT, gas: 4500000 });

  console.log('Voting');
  res = await voter.methods['vote(uint256)'](1).call({ from: ACCOUNT, gas: 4500000 });
  console.log(res);

  console.log('getVotes');
  res = await voter.methods.getVotes().call({ from: ACCOUNT, gas: 4500000 })
  console.log(res);
}

(async () => {
  try {
    await sendTransaction();
    console.log('successfully voted');
  } catch (e) {
    console.log('Error:');
    console.log(e);
  }
})();

But I get the error:

Adding option tea
null
Adding option coffee
null
Start voting
Voting
Error:
TypeError: Cannot read property 'type' of undefined
        at getParamCoder (/Users/username/solidity-project/node_modules/ethers/utils/abi-coder.js:866:39)

I'm using web3 1.0.0-beta.55 and truffle 5.0.26. I managed to avoid this issue by adding a return type uint to vote function and returning an integer. But I'm trying to fix it without adding return type. Any ideas?

  • Did you forget to call method (smart contract function) after methods in res = await voter.methods['vote(uint256)'](1).call({ from: ACCOUNT, gas: 4500000 }); @Dominik – Harsh Jul 11 at 5:41
  • No. methods['vote(uint256)'] is selecting a method vote with parameter uint256 and (1) is a method call. I also tried with voter.methods.vote(0), but still get the same output. @Harsh – Dominik Dragičević Jul 11 at 7:22
  • Try using send instead of call as call is to call a function (which does not change the state of a contract) where as send is used to change the state of a smart contract. Use this link [web3js.readthedocs.io/en/1.0/… for reference. @Dominik – Harsh Jul 11 at 9:46
  • @Harsh Yes, that did the trick! Thanks! I also needed to add { transactionConfirmationBlocks: 3 } parameter into my contract initialization in order to .send work with await. Otherwise, it would just hang. So the voter initialization now looks like this: const voter = new web3.eth.Contract(abi, VOTER_CONTRACT_ADDRESS, { transactionConfirmationBlocks: 3 }) – Dominik Dragičević Jul 11 at 11:27
  • Cool. Good to here that. :) – Harsh Jul 11 at 12:14

Your Answer

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

Browse other questions tagged or ask your own question.