EVM Accesslist (Ethereum/Polygon)

Merkle Tree and Mapping Based Accesslist Support

Merkle Tree Based Accesslist

Using a merkle tree for the accesslist phase on an evm drop is a little more involved, but is more secure and more gas efficient.

Here is an example accesslist mint function:

// SPDX-License-Identifier: MIT
// Credits to Albert Lin
pragma solidity ^0.8.11;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract PrimitiveWhiteList is ERC721Enumerable, Ownable {
    using ECDSA for bytes32;
    uint256 public constant MINT_PRICE = 0.001 ether;
    bytes32 private _merkleRoot;
    constructor() ERC721("Merkle Tree Accesslist", "MTA") {}
    function accesslistSale(address to, bytes32[] memory proof, uint256 amount) external payable {
        // merkle tree list related
        require(_merkleRoot != "", "merkle root not set");
                keccak256(abi.encodePacked(to, amount))
            "accesslist validation failed"

        // start minting
        uint256 currentSupply = totalSupply();

        for (uint256 i = 1; i <= amount; i++) {
            _safeMint(to, currentSupply + i);
    function setMerkleRoot(bytes32 newMerkleRoot_) external onlyOwner {
        _merkleRoot = newMerkleRoot_;

Please contact a tech support engineer in our discord to set up your accesslist mint with Crossmint.

After creating a ticket, please provide the following information:

  1. Your Crossmint clientId for the collection
  2. A list of addresses that should be included in the accesslist phase. (Email, SOL, or EVM)


Why do we need a list of addresses from you?

Crossmint users can login with email, metamask, or phantom wallets. That login is then linked to unique custodial wallets that actually receive the NFT. It is this custodial wallet address that we pass to the _to parameter in your mint function. These custodial wallets must be included in the merkle root so that we can create a valid proof for them to mint during the accesslist phase.

Once an engineer picks up your support ticket we will do the following:

  1. Provide a list of Crossmint custodial wallets we generated for the list you provided.
  2. If applicable we will also provide you with a Merkle root hash generated from the list.

Mapping Based Accesslists

The simplest form of whitelisting involves maintaining a mapping in your smart contract that holds the addresses of whitelisted supporters.

mapping(address => uint256) public whitelistMapping;

This example would map the address for a user to how many tokens they can mint during the presale phase. The presale mint function ensures the minter is in the mapping and has tokens remaining.
Here is an example of what the presale function could look like:

function presale(address _to, uint256 _count) external payable {
    // ensure _to address has tokens left to mint
    require(whitelistMapping[_to] > 0, "no whitelist tokens for user");
    // decrement mapping for user
    whitelistMapping[_to] -= _count;
    // presale minting logic here

Some important considerations of this approach are worth mentioning.

  • Your contract will need an owner only way to add addresses to the whitelistMapping.
  • This approach is inefficient in terms of gas cost. If you have a large whitelist you should avoid this approach, especially if the blockchain is ethereum.
  • It is possible for savvy developers to determine the addresses in your whitelist.