2

Lets take a very basic smart contract that has one function in which you send a number and it will return the square. It has another function that returns a fixed string.

contract MyContract {
  uint public version;
  address public previousPublishedVersion;

  function ping() returns (string param){
    param = "pong";
  }

  function squareNumber(uint num) returns (uint256 numSqr) {
    numSqr = (num * num);
  }
}

Now to deploy the contract I use

myContract.new({
  data: MyContract.compiled_code,
  gas: gasNeeded * ethConfig.gas_factor,
  from: ethConfig.primary_address
}, (err, myContract) => {
    if(!err) {
     if(!myContract.address) {
         console.log('contract trasnaction hash ' + myContract.transactionHash)
     } else {
        console.log('contract address ' + myContract.address)
        resolve({
         primary_address: ethConfig.primary_address,
         contract_address: myContract.address,
         gas_estimate: gasNeeded
        })
     }
  } else {
    reject(err)
  }
});

This fires two callbacks, one with the transaction hash and one with the address once its mined. However this method is not there for sendTransaction. I have read that using getTransactionReceipt or checking block numbers is a good way to check whether the transaction has been mined or not.

  myContract.ping.call(null, (err, data) => {
    if (err) {
      reject(err)
    } else {
      resolve({
        primary_address: ethConfig.primary_address,
        returnValue: data
      })
    }
  })

But for squaring the number I use

  myContract.squareNumber.estimateGas(10, (err, gasNeeded) => {
    if (err) reject(err)
    myContract.squareNumber.sendTransaction(
      10,
      {
        gas: gasNeeded * config.ethConfig.gas_factor,
        from: config.ethConfig.primary_address
      }, (err, data) => {
      if (err) reject(err)
      resolve({
        primary_address: config.ethConfig.primary_address,
        numSquare : data
      })
    })
  })

Now for a call function, I can get the data directly without any mining to be done, however the docs say that the value returned from sendTransaction() is the hash of it, and then we are to use getTransactionReceipt() to actually confirm when the block was mined.

My question is simply this, how exactly do I structure my web3js code, to get the value returned (10*10) from the solidity function squareNumber().

I have wrapped all APIs shown above in promises but just skipped that part as its long and not related to web3js in any way.

2 Answers 2

2

After adding an event like SquareComputed (see How to get values returned by non constant transaction functions?) and web3.js Contract Events example

var event = myContractInstance.MyEvent({valueA: 23} [, additionalFilterObject])

// watch for changes
event.watch(function(error, result){
  if (!error)
    console.log(result);
});

this would lead to code like:

var event = myContractInstance.SquareComputed({});

// watch for changes
event.watch(function(error, result){
  if (!error)
    resolve({
        primary_address: config.ethConfig.primary_address,
        numSquare : result  // need to access the properties of result to obtain the actual square 
    })
  event.stopWatching();
});

Do the above before myContractInstance.squareNumber.sendTransaction. The resolve({numSquare:...}) in the original code should be moved to inside the watch as above.

Other web3.js APIs such as web3.eth.filter can also be used (see How do I retrieve the Voted events from The DAO).

This questions asks "how exactly do I structure my web3js code, to get the value returned (10*10) from the solidity function squareNumber()", otherwise for an overview see What is the difference between a transaction and a call?.

2
  • Understood what you wrote and the links, however if I have multi instances of this contract created on the blockchain, say each person has his own unique contract instance deployed, then using event.watch will become problematic cause it will pick up any event logs fired. Commented Jan 16, 2017 at 13:06
  • If each user has their own contract and own UI, above could work. If each user has multiple contracts, maybe an array could be used like: event[i] = myContractInstance[i].SquareComputed({}). Another possibility is to have an indexed parameter to the event like userId, and filter on it like event = myContractInstance.MyEvent({userId: 23} (May need to ask separate question if we get too abstract and need to be specific.)
    – eth
    Commented Jan 16, 2017 at 13:15
0

With Web3.js v1.0.0 you can get the event fired by your SquareComputed transation (sendTransation() equivalent method is now send()), see send() return in the documentation

Your Answer

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

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