Merkle Machine
⚙️
🌲
Generate merkle trees for ethereum smart contracts
Addresses (0)
Seperate with new line, comma, space, or emojis. It doesn't matter.
Merkle root
This is the root that you use in the contract to verify the proofs against.
Download as Next.js API
Ready to use typescript API for Next.js
The files go here in your Next.js project
/src
proofs.ts <-- here
/pages
/api
merkle.ts <-- here
The proofs.ts file will be huge if you have a big collection.
It doesn't matter, it is still faster than generating the proof on the fly.
To get the proof call /api/merkle with a GET request
and address as a query parameter.
Example:
/api/merkle?address=0x70804f88A50090770cBdA783d52160E7E95d7822
Download as JSON
In case you don't want to use the Next.js API.
Solidity example
Use ERC721A and Solady instead of Open Zeppelin.
They are more gas efficient.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "erc721a/contracts/ERC721A.sol";
import "vectorized/solady/src/utils/MerkleProofLib.sol";
import "vectorized/solady/src/auth/Ownable.sol";
contract WhitelistMint is ERC721A, Ownable {
error InvalidProof();
error AlreadyMinted();
bytes32 merkleRoot;
constructor(bytes32 _merkleRoot) ERC721A("WhitelistMint", "WM") {
// Adds initial merkle root.
merkleRoot = _merkleRoot;
// Initializes the owner directly without authorization guard.
_initializeOwner(msg.sender);
}
/// @dev Mints a token to the msg.sender, if the merkle proof is valid.
/// @param _merkleProof The merkle proof that will be used for verification.
function mint(bytes32[] calldata _merkleProof) external payable {
// This is where the merkle proof verification happens
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
if (!MerkleProofLib.verifyCalldata(_merkleProof, merkleRoot, leaf)) revert InvalidProof();
// We check if the proof has been used before.
if (_getAux(msg.sender) != 0) revert AlreadyMinted();
// We set the aux to 1, to indicate that the proof has been used.
_setAux(msg.sender, 1);
_mint(msg.sender, 1);
}
/// @dev Sets the merkle root to a new value.
/// @param _merkleRoot The new merkle root.
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
merkleRoot = _merkleRoot;
}
}
TypeScript proof generation
In case you want to generate the proofs yourself.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import keccak256 from "keccak256";
import MerkleTree from "merkletreejs";
import { addresses } from "./addresses";
const makeProof = (address: string, tree: MerkleTree) => {
const proof = tree.getHexProof(keccak256(address));
return proof;
};
const makeTree = () => {
const leaves = addresses.map((addr) => keccak256(addr));
const tree = new MerkleTree(leaves, keccak256, { sortPairs: true });
return tree;
};
// Example usage making proof for first address
const tree = makeTree();
const proof = makeProof(addresses[0], tree);
console.log(proof);