I’m working on a smart contract for an NFT project. I want to let people mint one free NFT each as part of a promo. How can I make a function that lets anyone mint just one token without paying (except gas fees)?
Here’s what I’ve got so far:
contract FreeNFTMint is ERC721, ERC721Enumerable, Ownable {
bool public freeClaimOpen = false;
uint256 public freeTokensLeft = 100;
function claimFreeNFT() public {
require(freeClaimOpen, "Free claim is not open yet");
require(freeTokensLeft > 0, "No more free tokens left");
// Need help here to limit one per user
uint256 tokenId = totalSupply();
_safeMint(msg.sender, tokenId);
freeTokensLeft--;
}
}
Right now, anyone can mint multiple times. How do I change it so each address can only mint once? Also, is there a way to do this without centralized tracking? Any tips or code examples would be great. Thanks!
To implement a single free mint per user, you can utilize a mapping to track claimed addresses. Here’s how you could modify your contract:
mapping(address => bool) public hasClaimed;
function claimFreeNFT() public {
require(freeClaimOpen, "Free claim is not open yet");
require(freeTokensLeft > 0, "No more free tokens left");
require(!hasClaimed[msg.sender], "Address has already claimed");
uint256 tokenId = totalSupply();
_safeMint(msg.sender, tokenId);
hasClaimed[msg.sender] = true;
freeTokensLeft--;
}
This approach ensures each address can only mint once. It’s simple and gas-efficient for smaller projects. However, for larger-scale distributions, consider exploring more advanced techniques like merkle proofs to optimize gas costs.
hey climbing mountain! cool project ur working on 
i was wondering, have u considered using an alternative approach like a merkle tree for whitelisting addresses? it could be more gas-efficient for larger free mint lists.
also, what’s ur plan for preventing bots from snatching up all the free mints? maybe add a small time delay or captcha?
btw, love the idea of a free promo mint! what kind of artwork are u planning for the nfts?
keep us updated on how it goes!
Hey ClimbingMountain, here’s a quick fix:
use a mapping to track minted addresses:
mapping(address => bool) public hasClaimed;
function claimFreeNFT() public {
require(!hasClaimed[msg.sender], \"Already claimed\");
// rest of ur code
hasClaimed[msg.sender] = true;
}
this’ll do the trick! lmk if u need anything else