It's 2023, can we PLEASE stop writing mint functions like this in NFT contracts?
Please bookmark this tweet and keep it in your back pocket for the next NFT contract you need to write.
Mint functions are some of the easiest functions to get right and have the biggest direct impact on the transaction fees paid by the users...
Yet so many people are still doing it very inefficiently...
This is the mint logic for the current #1 trending collection on OpenSea...
What do we see wrong here?
1. maxMintAmountPerTx isn't really indicative of what it REALLY means. This isn't the max amount that you can mint PER transaction, it's the max amount that each address can mint IN TOTAL. Not the biggest deal, but it's always good to appropriately name things for clarity.
2. The contract allows a user to mint 25 NFTs at a time. This is a PERFECT candidate for ERC721A. This is the bulk of the unnecessary gas consumption.
3. Due to minting in a loop, they are needing to increment their supply counter and read from it every time. That's a lot of unnecessary storage operations. OpenZeppelin has deprecated counters, just ditch them all together.
Now let's optimize this function...
The changes were VERY simple...
Here's what we did:
1. Inlined the logic from their mintCompliance modifier.
2. Switched from require statements to reverts with custom errors. Cleaner to look at in my opinion and cheaper in the event of a revert.
2. Switched from ERC721 to ERC721A. I feel like a broken record here, but any time you are allowing multiple mints in a single transaction I would strongly recommend the usage of ERC721A. This library updates state after the mint loop rather than every iteration. This drastically cuts down on the amount of SSTORE operations and in turn saves a MASSIVE amount of gas.
3. Because we're using ERC721A, we are also only updating the current counter ONCE, as opposed to N times, where N is the number of mints.
Okay, now on to the juicy part. The results:
Our test case minted 25 NFTs, which is the maximum amount per wallet that was defined in the original contract.
The optimized version is over FOUR times more efficient.
Please do note though, foundry does not include the base 21,000 gas transaction fee.
For an experienced developer, this may all be common sense, but the main goal of these threads is to educate newer developers, and hopefully guide them in the right direction so that they write efficient smart contracts earlier rather than later.
gas bad