7

if I keccak256(string1, address1) in Solidity, and then use web3.sha3(string1, address1) in web3.js, I get different results, even though when I do both with only string1 as a single argument, they are the same results. I have tried passing {encoding: 'hex'} to the web3 call but it still gives different results.

Does anyone know how to make web3.sha3(...args), with any arguments (uint, address, string, etc) exactly equal to keccak256 in Solidity?

5

You can use web3.utils.soliditySha3()

Alternatively you can try this way:

web3.sha3(web3.toHex(string1) + address1, {encoding:"hex"});

Note that address1 should not be prefixed with 0x.

Example:

> web3.sha3(web3.toHex("test1") + "0AbdAce70D3790235af448C88547603b945604ea", {encoding:"hex"});
"0xd7ced52b610c8794965f5bb365f280999a9790b147bd0dfc70dea6edb2616c15"

Produces the same result as this code in Solidity:

keccak256("test1", 0x0AbdAce70D3790235af448C88547603b945604ea);

Does anyone know how to make web3.sha3(...args), with any arguments (uint, address, string, etc) exactly equal to keccak256 in Solidity?

You need to make sure that the 1st argument that you pass to web3.sha3() function is equal to the tightly packed arguments for keccak256 function in Solidity. The easiest way is to use web3.toHex() for each argument (except addresses as they are already in hex), then concatenate the results and set encoding to hex in the options for web3.sha3() as I've shown in the example.

2

I managed to find the function in this issue to work for all cases (apart from negative numbers, as you will see in the comments in the issue):

function keccak256(...args) {
  args = args.map(arg => {
    if (typeof arg === 'string') {
      if (arg.substring(0, 2) === '0x') {
          return arg.slice(2)
      } else {
          return web3.toHex(arg).slice(2)
      }
    }

    if (typeof arg === 'number') {
      return leftPad((arg).toString(16), 64, 0)
    } else {
      return ''
    }
  })

  args = args.join('')

  return web3.sha3(args, { encoding: 'hex' })
}
2

soliditySha3 will do the trick:

const hashKey = web3.utils.soliditySha3('string', object.param,'rewardAmount', string, address)

2

in js application, require "left-pad" module,such as :let leftPad = require('left-pad');

function T_keccak256(...args){
args = args.map(arg => {
    if(typeof arg === 'string'){
        if(arg.substring(0,2) === '0x'){
            return arg.slice(2)
        }else {
            return web3.fromAscii(arg).slice(2)
        }
    }
    if(typeof arg === 'number'){
        return leftPad((arg).toString(16),64,0)

    }else {
        return ''
    }
})
args = args.join('');
return web3.sha3(args, { encoding: 'hex'});

in Solidity ^5.0,use keccak256(abi.encodePacked(arg1,arg2,...)) .

1

The simple answer is to use web3.utils.soliditySha3.

But the way to use it is what makes all the difference.

const theValueYouNeed = web3.utils.soliditySha3(
{ type: 'bytes32', value: theBytes32Value },
{ type: 'address', value: theAddressValue },
{ type: 'bytes32', value: 'IfYouAreDirectlyPuttingValueUseQuotes' });

This way you will get the same result as the value you get from the Solidity function below:

function hashThat(bytes32 theBytes32Value, address theAddressValue, bytes32 anotherValue) public view returns(bytes32 hashedValue){
    return keccak256(abi.encodePacked(theBytes32Value, theAddressValue, anotherValue));
}

Note: I am using web3@1.2.1 and solidity >=0.4.22 <0.6.0

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.