3

I'm trying to create a whitelist for an NFT using a Merkle tree to save on gas costs. I saw a great implementation here, in javascript, but I would like to do it in Python. Doesn't seem like I'm able to create a merkle tree using keccak hashing, which I think it necessary to do for the etheruem blockchain. Open-zeppelin's MerkleProof.sol uses kaccack hashing to verify a leaf. I'm guessing I can just change this to use sha256 instead, but I don't like these quick fixes.

Here is what I tried below:

from pymerkle import MerkleTree
from Crypto.Hash import keccak
from scripts.helpful_scripts import get_account
from brownie import NFTCollectible, network, config


def hash(address):
    k = keccak.new(digest_bits=256)
    k.update(address.encode("utf_8"))
    return k.hexdigest()


def main():
    account = get_account()
    nft_collectible = NFTCollectible[-1]

    whitelistedAddresses = [
        "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4",
        "0x78D6CF3DEF45AF458442E787FE6E64A03750AB94",
        "0xA7B0E4CF55AF900F6E80D619AE1E00965044BC4E",
        "0x38C4278F42A26A588176017F5E4F6ED831835EA2",
        "0x9F9A0AA0507FE79CA1FF8F26A8D84BD8BB0EC9DF",
        "0xDABF258F5619942D19AD87C3472FABE893B26D7D",
        "0xD30ED9C457C7D32F3F7B949964191E4084C53F66",
    ]

    leafNodes = []
    for address in whitelistedAddresses:
        hashedAddress = hash(address)
        leafNodes.append(hashedAddress)

    merkleTree = MerkleTree()
    for leaf in leafNodes:
        merkleTree.update(leaf)

    print(merkleTree)

    root = merkleTree.rootHash.decode("utf-8")
    print(root)

It does return a Merkle tree, but hashed using sha256 as pymerkle doesn't have keccak hashing. (The keccak library above is used for hashing the wallets). Running this returns a different Merkle tree than the one in JS. I'm not even sure if the difference is because of the hashing.

This is how I would like to verify in solidity:

        // using merkle tree for whitelist
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); // this will work good since the wallets are hashed by keccak
        require(
            MerkleProof.verify(merkleProof, whitelistedMerkleRoot, leaf), // this will fail
            "Not on the whitelist"
        );
frankied003
  • 466
  • 6
  • 26

2 Answers2

0

Did you try overriding existing Pymerkle methods in order to be able to use a new encoding option ?

You would need to include type here https://github.com/fmerg/pymerkle/blob/6d4c9eb502fe7aa6117123e7f1ab8cf84a38e7b4/pymerkle/hashing/machine.py#L9

0

I made a package specifically for this reason... was sick of using javascript in my Brownie projects haha.

The MerkleTreeKeccak class should do exactly what you want. You have to supply hashed addresses as the leaves, just as you do with merkletreejs.

https://pypi.org/project/evm-sc-utils/

Maroc
  • 1