10
votes

I am trying to call a method on my ERC20 token contract. I am connecting to 'https://rinkeby.infura.io/' httpProvider. I can call() constant methods but when i want to change the state of the contract by calling send() function i get this mentioned error. If you think posting the ABI JSON or the Solidity contract helps, i can provide it as well. I thought my issue is purely web3 related. I think i need to sign transactions (logically) but the web3 documentation doesn't mention anything. http://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#methods-mymethod-send

This is the error i've been getting:

Unhandled rejection Error: Invalid JSON RPC response: ""
at Object.InvalidResponse (/opt/backend/node_modules/web3-core-helpers/src/errors.js:42:16)
at XMLHttpRequest.request.onreadystatechange (/opt/backend/node_modules/web3-providers-http/src/index.js:60:32)
at XMLHttpRequestEventTarget.dispatchEvent (/opt/backend/node_modules/xhr2/lib/xhr2.js:64:18)
at XMLHttpRequest._setReadyState (/opt/backend/node_modules/xhr2/lib/xhr2.js:354:12)
at XMLHttpRequest._onHttpResponseEnd (/opt/backend/node_modules/xhr2/lib/xhr2.js:509:12)
at IncomingMessage.<anonymous> (/opt/backend/node_modules/xhr2/lib/xhr2.js:469:24)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1055:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
From previous event:
at PromiEvent (/opt/backend/node_modules/web3-core-promievent/src/index.js:35:24)
at send (/opt/backend/node_modules/web3-core-method/src/index.js:446:21)
at Object._executeMethod (/opt/backend/node_modules/web3-eth-contract/src/index.js:890:24)
at Object.currencyToken.sendSignUpBonousTokens (/opt/backend/server/common/token/currency-token.js:86:56)
at <anonymous>

From calling this method:

const Web3 = require('web3');
const Tx = require('ethereumjs-tx');
const ABIjson = require('./ABI.json');

const web3 = new Web3(new Web3.providers.HttpProvider('https://rinkeby.infura.io/my_access_token_here'));
const contractAddress = '0x31cF32fa91286168B1A896Db4F99d106246932Bc';
const ownerAddress = '0x44Ba8c5a905D634c485dE6f8fD43df9682AfD342';

const token = new web3.eth.Contract(ABIjson, contractAddress);
try
{
    const gasAmount = await token.methods.transfer(company.walletAddress, 10000).estimateGas({from: ownerAddress});

    token.methods.transfer(company.walletAddress, 550).send(
      {
        from: ownerAddress,
        gasPrice: '20000000000',
        gas: gasAmount
      })
      .then(function(receipt)
      {
        console.log(receipt);
      });
}
catch (error)
{
    console.error(error);
}

Here is the ABI snippet for the method:

{  
"constant":false,
"inputs":[  
  {  
    "name":"_to",
    "type":"address"
  },
  {  
    "name":"_value",
    "type":"uint256"
  }
],
"name":"transfer",
"outputs":[  
  {  
    "name":"success",
    "type":"bool"
  }
],
"payable":true,
"stateMutability":"payable",
"type":"function"
},
1
Yes, you need to sign the transaction. See ethereum.stackexchange.com/questions/26999/…Adam Kipnis

1 Answers

1
votes

@sam k, here's a better more comprehensive solution to what you're probably looking for. There's one important thing I've noticed in your given code-snippet, you have not included an httpProvider line in your code and that might be the reason (there may be other reasons as well). So kindly add the line mentioned below.

let contractABI = <your contract ABI>;
let contractInstance = new web3.eth.Contract(contractABI, 
contractAddress);
/**The line below needs to be added, specifying the http provider*/
contractInstance.setProvider(new Web3.providers.HttpProvider(URL));

Now comes the part where you want to "SIGN" transactions that impose a "state" change to your contract. So you can follow the following code structure in order to sign a transaction.

web3.eth.getTransactionCount(ownerAddress).then( (nonce) => {
    let encodedABI = 
contractInstance.methods.statechangingfunction(<arguments>).encodeABI();
/**Estimating the required gas automatically from the network itself*/
contractInstance.methods.statechangingfunction(<arguments>).estimateGas({ from: ownerAddress }, (error, gasEstimate) => {
      let tx = {
        to: contractAddress,
        gas: gasEstimate,
        data: encodedABI,
        nonce: nonce
      };
      /** Signing the transaction with the "privateKey" of the owner*/
      web3.eth.accounts.signTransaction(tx, privateKey, (err, resp) => {
        if (resp == null) {console.log("Error!");
        } else {
          let tran = web3.eth.sendSignedTransaction(resp.rawTransaction);
          tran.on('transactionHash', (txhash) => {console.log("Tx Hash: "+ txhash);});

If your rest of the code is fine, this solution should work. In case it doesn't then I would suggest you comment the github link to your project's repo, so that I can review and provide a solution. Let me know if this helps. You may refer to these official web3 links: signTransaction, sendSignedTransaction, getTransactionCount and estimateGas.