Skip to content

Instantly share code, notes, and snippets.

@Hero-Development
Created March 11, 2023 17:07
Show Gist options
  • Save Hero-Development/868cceebb96d8c3e21cd4ac3be21d136 to your computer and use it in GitHub Desktop.
Save Hero-Development/868cceebb96d8c3e21cd4ac3be21d136 to your computer and use it in GitHub Desktop.
Full Merkle Tree Example
/**
* Description: an example using merkle.js
**/
import Merkle from 'merkle';
const allowList = [
'0x0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000002',
'0x0000000000000000000000000000000000000003',
'0x0000000000000000000000000000000000000004'
// etc
];
const merkle = new Merkle();
// TODO: override `normalize()` for complex leaves
merkle.load(allowList);
// set this on your smart contract
const root = merkle.getHexRoot(); //hex string
// when the user tries to mint, get their proof
const proof = merkle.getProof( account ); //hex string[]
await contract.method(param1, param2, proof);
/**
* Description: a simple wrapper for `keccack256` and `merkletreejs` making it easy to:
* - load accounts
* - generate proofs
* - associate extra data
* - upgrade to complex leaves (override `normalize()` as needed)
*
* Prereqs:
* yarn add keccack256 merkletreejs
* pick one:
* - ethers (comes with WAGMI)
* - web3
**/
import ethers from 'ethers';
//import Web3 from 'web3';
import keccak256 from 'keccak256';
import { MerkleTree } from 'merkletreejs';
class Merkle{
accounts = {};
tree = null;
getHexRoot(){
return this.tree.getHexRoot();
}
getProof(account){
account = account.toLowerCase();
if(account in this.accounts){
return this.tree.getHexProof(this.accounts[account].leaf);
}
else{
return [];
}
}
load(accounts){
accounts.sort();
const leafNodes = accounts.map(account => {
const normalized = this.normalize(account);
const leaf = keccak256(normalized);
this.accounts[account.toLowerCase()] = {
account,
leaf,
};
return leaf;
});
this.tree = new MerkleTree(leafNodes, keccak256, { sortPairs: true });
}
normalize( account ){
try{
return ethers.utils.getAddress( account );
//return Web3.utils.toChecksumAddress( account );
}
catch( err ){
return account;
}
}
}
export default Merkle;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract Merkle{
bytes32 public merkleRoot = "";
// TODO: implement a setter
// function setMerkleRoot(bytes32 merkleRoot_) external onlyOwner {
// merkleRoot = merkleRoot_;
// }
function _isValidProof(bytes32 leaf, bytes32[] memory proof) internal view returns(bool) {
return MerkleProof.processProof(proof, leaf) == merkleRoot;
}
}
/**
* Example:
**
contract X is Merkle{
error NotAuthorized();
function mint(uint256 quantity, bytes32[] calldata proof) external payable {
bytes32 leaf = keccack256(msg.sender);
if(!_isValidProof(lead, proof))
revert NotAuthorized();
}
// TODO: implement a merkle root setter
// function setMerkleRoot(bytes32 merkleRoot_) external onlyOwner {
// merkleRoot = merkleRoot_;
// }
}
**/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment