8

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

2 Answers 2

11

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.

6
  • 2
    Thank you. I was feeling that is annoying. (hash and get 4bytes and add param...) I'll try to use it.
    – zono
    Jul 17, 2017 at 6:49
  • I will also check about web3.eth.sendTransaction
    – zono
    Jul 17, 2017 at 6:57
  • Sure. It's really annoying. I was also stuck in doing all this unnecessary stuff until I discovered getData. Jul 17, 2017 at 7:06
  • 1
    I believe it's const contract = new web3.eth.Contract(contractABI, contractAddress) these days (web3 1.6.1)
    – YakovL
    May 5, 2022 at 12:52
  • 1
    You can have a look at another question here that has parts of getting data and sendng tx. May 7, 2022 at 13:35
3

Even I had to go through the same process until i discovered, the below:

use the web3.js library which helps in doing the same. Just download web3.js using NPM (or anywhere else) and get the modules required for the task, by:

const_ = require('lodash');
const SolidityFunction = require('web3/lib/web3/function');

You can use the web3.js library along with your ABI to find the function definition, using the below code:

var ABI = JSON.parse(<your_ABI>);
var functionDef = new SolidityFunction('', _.find(ABI, { name: '<your_function_name>' }), '');

After this, you can call the method toPayload which will help you converting the values that you want to pass to your function into HEX Data.

var payloadData = functionDef.toPayload([<value_for_var_1>, <value_for_var_2>, <value_for_var_3>, <value_for_var_4>]).data;

payloadData can be used as Value for the DATA property. Example:

var rawTx = {
 to: <to_address>,
 data: payloadData,
 value: '0x0',
 from: <from_address>,
 nonce: nonce,// You need to Get this using web3.eth.getTransactionCount
 gasLimit: gasLimit, // Get this by web3.eth.estimateGas
 gasPrice: gasPrice // use, web3.eth.gasPrice
}

You can use this approach and forget about how many zeros to pad with. As the toPayload function handles everything. You have a raw transaction object, you can use ethereumjs-tx to sign your transaction and use web3.eth.sendRawTransaction to call your Contract Function.

Hope this helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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