Jehan's answer is great, but we need to explain one more thing: Why does sha3(1)
in solidity produce b10e2d...fa0cf6
?
This is because solidity's sha3 function hashes its inputs based on the argument types. Thus the value 1
will generate a different hash if it is stored as bytes8
, bytes16
, bytes32
, etc. Since sha3(1)
is being passed 1
as a number literal, it is converted into the smallest necessary type, uint8
1.
8 bits fit into 2 hex characters, so if you pad your input to 2 characters you will get the same result in web3:
Javascript:
web3.sha3(leftPad((1).toString(16), 2, 0), { encoding: 'hex' })
// 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2
Likewise, you can cast the number on the solidity side:
Solidity:
// uint is equivalent to uint256
sha3(uint(1))
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
Javascript:
// note that the value is padded by 64 characters to fit 256 bits
web3.sha3(leftPad((1).toString(16), 64, 0), { encoding: 'hex' })
// b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6
A note about BigNumber
types:
They don't work automatically with web3.sha3
. You have to convert them to hex first.
Solidity:
sha3(uint(100 ether))
// c7cc234d21c9cfbd4632749fd77669e7ae72f5241ce5895e410c45185a469273
Javascript:
// the .slice is to remove the leading '0x'
web3.sha3(leftPad(web3.toHex(web3.toWei(100)).slice(2).toString(16), 64, 0), { encoding: 'hex' })
// c7cc234d21c9cfbd4632749fd77669e7ae72f5241ce5895e410c45185a469273
EDIT:
I wrote a small lib that provides a version of web3.sha3
that exactly matches the behavior of sha3
in Solidity. Hopefully this clears up all your hashing woes :).
https://github.com/raineorshine/solidity-sha3
I think the contract address or ABI is not correctly set in your case because I tested and it works perfectly.
Please check if correct contract address and ABI is updated in your javascript file.
[Update]
-----------------------
As you asked, I am attaching my code:
Solidity Code:
pragma solidity ^0.4.0;
contract testContract {
uint256 num1;
address[] contracts = [0x36eaf79c12e96a3dc6f53426c, 0xf235aa56dd96bda02acfb361e];
function getContractsCount() constant returns (uint256) {
return contracts.length;
}
}
jQuery code:
$(document).ready(function(){
function contractInvocation() {
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
var abi = <ABI>;
var testContract = web3.eth.contract(abi);
var contractInstance = testContract.at('<Contract Address>');
var y = contractInstance.getContractsCount.call({from:web3.eth.accounts[0]}).c[0];
console.log(y);
});
Best Answer
Using BN.js as suggested by @Ismael: