2

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?

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

var 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.

var Web3 = require('web3');
var 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

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

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

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

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

var 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()

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

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

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

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

var contract = web3.eth.contract(contractABI).at(contractAddress);
var callData = contract.functionName.getData(functionParameters);
var 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.

  • 1
    Thank you. I was feeling that is annoying. (hash and get 4bytes and add param...) I'll try to use it. – zono Jul 17 '17 at 6:49
  • I will also check about web3.eth.sendTransaction – zono Jul 17 '17 at 6:57
  • Sure. It's really annoying. I was also stuck in doing all this unnecessary stuff until I discovered getData. – Prashant Prabhakar Singh Jul 17 '17 at 7:06
2

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, privacy policy and cookie policy

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