[Ethereum] web3.eth.call. How to set “data” param

contract-invocation

I deployed my first contract by using browser-solidity to make bytecode and web3.eth.sendRawTransaction to deploy.
The following is the transaction and the deployed contract code.

https://ropsten.etherscan.io/tx/0x74426948905cd6e70e8b9d64a660b3c179b7c8a224ca5cd0234842768eb501db

contract code

pragma solidity ^0.4.0;
contract Addition {
  int num = 0;
  function add(int a){
    num += a;
  }
  function get() returns(int){
    return num;
  }
}

Then, I want to call the two methods by web3.eth.call. However, I can't find a way how to generate the "data" param. Could you please give me any advices?

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://xxx:xxx"));

const result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a", 
    data: "???"
});

https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcall

I think gas is needed to call but this example does not mention about it. On JavaScript VM on browser-solidity, the prices are showed when I execute the method like below.

Result: "0x"
Transaction cost: 41713 gas. 
Execution cost: 20249 gas.

Update 1

Seems this page describes about it.

I then wanted to call the method "double" with the number "5". The Contract ABI documentation says that you have to take the first 4 bytes of the Keccak hash.
The method signature is

double(int)

Which gives the hash with web3.sha3("double(int)":

6740d36c7d42fba12b8eb3b047193c9761224c267d7a2e96dc50949860652317

The first four bytes, prefixed with "0x" are:

0x6740d36c

The documentation then tells to take the parameter, encode it in hex and pad it left to 32 bytes. Which would be the following, using the number "5":

0x0000000000000000000000000000000000000000000000000000000000000005

In total, the encoded string should look like this:

0x6740d36c0000000000000000000000000000000000000000000000000000000000000005

How to call a contract method using the eth_call JSON-RPC API


Update 2

It does not work.

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://xxx:xxx"));

var result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
    data: "0x6d4ce63c" // var hash = web3.sha3("get()"); get first 4 byte
});

console.log(result); // 0x

var result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
    data: "0x250fc6d90000000000000000000000000000000000000000000000000000000000000001" // var hash = web3.sha3("add(int)"); get first 4 byte and param (1)
});

console.log(result); // 0x

var result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
    data: "0x6d4ce63c" // var hash = web3.sha3("get()"); get first 4 byte
});

console.log(result); // 0x => I expected 1

Updata 3

I changed from add(int) to add(int256) but still does not work.

var result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
    data: "0x87db03b70000000000000000000000000000000000000000000000000000000000000001" // var hash = web3.sha3("add(int256)"); get first 4 byte and param (1)
});

However browser-solidity debugger shows the same data. So I think this data is correct.


Update 4

Seems I have to send transaction before call. I can imagine. I will try it.

Call. It is a read-only operation and will not consume any Ether.

What is the difference between a transaction and a call?


Update 5

Although I think found the answer but still it does not work. I'll take a break..

(1) sendRawTransaction

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://xxxx:xxxx"));

const Tx = require('ethereumjs-tx');
const privateKey = new Buffer('xxxx', 'hex')

const rawTx = {
  nonce: '0x03',
  gasPrice: '0x53d9',
  gasLimit: '0x53d9',
  to: '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
  data: '0x87db03b70000000000000000000000000000000000000000000000000000000000000001' // add(int256) with param 1
}

const tx = new Tx(rawTx);
tx.sign(privateKey);

const serializedTx = tx.serialize();

console.log('0x' + serializedTx.toString('hex')); // 0xf885038253d98253d994692a70d2e424a56d2c6c27aa97d1a86395877b3a80a487db03b700000000000000000000000000000000000000000000000000000000000000011ba0ec6de7c9c1f31dc95014156479925b2ebd933b715f2bb4450f5d74992d7b3423a016f6a7c6e1885412400a622f82ffa033936c06755896096c7638936c065571c1

web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {
  if (!err) {
    console.log(hash); // 0x26db79c7c3c65992f17f4f62d5d191705933e785dff54db6d27e6f3a92d7117e
  } else {
    console.log(err);
  }
});

https://ropsten.etherscan.io/tx/0x26db79c7c3c65992f17f4f62d5d191705933e785dff54db6d27e6f3a92d7117e

(2) call get()

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider("http://xxxx:xxxx"));

const result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
    data: "0x6d4ce63c"
});

console.log(result); // 0x => I expected 1

Best Answer

You don't need to do this all by yourself. You can instead use getData method.

const contract = new web3.eth.Contract(contractABI, contractAddress);
const callData = contract.functionName.getData(functionParameters);
const result = web3.eth.call({
    to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a", 
    data: callData
});

web3.eth.call executes the call in VM of the node but this is not mined. This is kind of dry run. If you instead want to send a transaction to blockchain use web3.eth.sendTransaction.