0

I want to create a hash in JavaScript for a signature. The hash needs to have the same output as this in solidity:

keccak256(abi.encodePacked(address, bytes32))

My solution in JavaScript so far produces a differing hash:

const types = ["address", "bytes32"];
const values = [myAddress, hash];
const message = ethers.utils.defaultAbiCoder.encode(types, values);
const hash = ethers.utils.keccak256(message);

How can I reproduce the code in Solidity in JavaScript?

5
  • Have you tried using abi.encode instead. For reference: ethereum.stackexchange.com/questions/119583/… Commented Jan 25, 2023 at 23:31
  • abi.encode as part of which package?
    – rajohs
    Commented Jan 25, 2023 at 23:34
  • in solidity the address is 20 byte array, the hash is 32 byte array. In Javascript what is your address? A string with 0x and hexadecimal characters? That would be an error. Same for the hash. You have to handle raw bytes in javascript
    – Nulik
    Commented Jan 26, 2023 at 0:41
  • encodePacked() is the correct function as 'packed' means that when the variable is smaller than 32 bytes it will be used as its true size is, if it is not packed, then it will be aligned on 32 bytes with prepended 0s and computed
    – Nulik
    Commented Jan 26, 2023 at 0:43
  • Are you sure that abi.encodePacked is used by defaultAbiCoder? You should really only use abi.encodePacked if you know what you are doing, as it can lead to hash collisions when used with dynamic types (see: discussion). The function abi.encode is available in Solidity Commented Jan 26, 2023 at 9:33

2 Answers 2

0

The discussion above explains the problem with my code already. Although in pieces.

I am using abi.encodePacked in my solidity code and ethers.utils.defaultAbiCoder.encode in my JS code.

encodePacked gives additional padding to the input variables to get it to 32 bytes, while encode takes them as is.

TLDR: I have to use the same encoding in JS ans Solidity.

0

The main issue in your JavaScript code is related to how data is encoded before hashing. In Solidity, keccak256(abi.encodePacked(address, bytes32)) uses a packed encoding. However, the ethers.utils.defaultAbiCoder.encode method does not produce a packed encoding; instead, it follows the standard ABI encoding, which includes padding to 32 bytes for each value.

In order to get the same hash as keccak256(abi.encodePacked(address, bytes32)) in Solidity, you need to use a packed encoding. You can use the ethers.utils.solidityPack function to achieve this. Here’s how to modify your code to generate the correct hash:

const ethers = require('ethers'); // or import ethers if using modules

const types = ["address", "bytes32"];
const values = [myAddress, hash];

// Using solidityPack for packed encoding
const packedData = ethers.utils.solidityPack(types, values);
const correctHash = ethers.utils.keccak256(packedData);

console.log(correctHash);

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.