Homer
1
I am using the MerklelProof contract of OpenZeppelin.
I generate a Merkle Tree off-chain. I do the following hashing for the leaves:
const leaf = keccak256('0x5B38Da6a701c568545dCfcB03FcB875f56beddC4', '707070');
hash = 5931b4ed56ace4c46b68524cb5bcbf4195f1bbaacbe5228fbd090546c88dd229
I calculate the hash for the same values in the smart contract (Solidity):
function retrieve() public view returns (bytes32){
bytes32 hash = keccak256(abi.encodePacked(msg.sender, '707070'));
return hash;
}
hash = 0x88b025b041de791b039533c721cfdc01de825e3a81e31e436db185334482cfdd
The first value is an address, the second an uint256.
How can I get the same hash values in Solidity as well as in Javascript?
How can I make sure to get the exact same hashes in Solidity (verify) and in Javascript (generation of Merkle Tree) ?
Homer
2
for(var i = 0; i < list.length; i++) {
var element = web3.utils.soliditySha3({t: 'address', v: '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4'}, {t: 'string' , v: '707070'});
myArray.push(element)
}
const tree = new MerkleTree(myArray, keccak256, {sort: true});
MerkleTree.print(tree);
That web3.utils.soliditySha
hash is the same as in Solidity, however, does not seem to work with
MerkleTree.
Homer
3
Smart Contract
pragma solidity ^0.8.0;
import "../node_modules/@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract Token {
bytes32 public merkleRoot;
event MerkleRootChanged(bytes32 merkleRoot);
event Leaf(bytes32 leaf);
function setMerkleRoot(bytes32 _merkleRoot) external {
require(merkleRoot == bytes32(0), "Token: Merkle root already set");
merkleRoot = _merkleRoot;
emit MerkleRootChanged(_merkleRoot);
}
function claimToken(uint256 tokenId, bytes32[] memory merkleProof) public returns (bool){
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, tokenId));
emit Leaf(leaf);
return MerkleProof.verify(merkleProof, merkleRoot, leaf);
}
}
Token.test
require('@openzeppelin/test-helpers');
const { MerkleTree } = require('merkletreejs');
const keccak256 = require('keccak256');
const token = artifacts.require('Token');
var testLeaves = [
'0x627306090abaB3A6e1400e9345bC60c78a8BEf57 258831',
'0x627306090abaB3A6e1400e9345bC60c78a8BEf57 166699',
'0xf17f52151EbEF6C7334FAD080c5704D77216b732 889988',
'0xC5fdf4076b8F3A5357c5E395ab970B5B54098Fef 707070',
'0x821aEa9a577a9b44299B9c15c88cf3087F3b5544 566396',
'0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2 888888',
'0x2932b7A2355D6fecc4b5c0B6BD44cC31df247a2e 333666',
'0x2191eF87E392377ec08E7c08Eb105Ef5448eCED5 658658',
'0x0F4F2Ac550A1b4e2280d04c21cEa7EBD822934b5 130779',
'0x6330A553Fc93768F612722BB8c2eC78aC90B3bbc 123456',
'0x5AEDA56215b167893e80B4fE645BA6d5Bab767DE 9998888',
];
contract('Token', function (accounts) {
beforeEach(async function () {
this.token = await F24.new();
console.log(accounts);
});
it('should return true for a valid leaf', async function () {
//const leaves = accounts.map(x => keccak256(x));
const leaves = testLeaves.map(x => keccak256(x));
console.log(leaves);
const merkleTree = new MerkleTree(leaves, keccak256, {sort: true});
MerkleTree.print(merkleTree);
const root = merkleTree.getRoot();
console.log("root: ",root);
var proof = merkleTree.getProof(leaves[0]).map(x => x.data);
console.log("proof: ", proof);
console.log("leaf: ", leaves[0]);
console.log(merkleTree.verify(proof, leaves[0], root, keccak256));
await this.token.setMerkleRoot(root, {from: accounts[0]});
expect(await this.token.claimToken(258831, proof, {from: accounts[0]})).to.equal(true);
});
});
I get different hashes in the MerkleTree (test) and in the smart contract.
I get only same hashes for msg.sender alone.
Any ideas?