NFT minting is expensive as shit. Let’s mint an ERC721-compatible NFT, that will work across the various marketplaces (Universe, OpenSea, Rarible, etc) without breaking the bank. The rules are simple: we can break ERC721-compliance, but we can not break compatibility. While following the standards we know and love is generally preferred, a little bit of non-compliance may be interesting at the very least, and actually productive at best.
Let’s start with Solmate’s ERC721 _mint() implementation, which is included in their gold standard, highly optimized boilerplate. Minting one NFT costs ~52,009 gas. Pretty damn good. As you can see, we first verify that we’re sending to a valid (non-zero) address, and then ensure that the token has not yet been minted. Afterwards we increment the users balance and assign them as the owner of the tokenID.
mapping(address => uint256) public balanceOf;
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), "INVALID_RECIPIENT");
require(ownerOf[id] == address(0), "ALREADY_MINTED");
// Counter overflow is incredibly unrealistic.
unchecked {
balanceOf[to]++;
}
ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
As we can see, there’s not much room to improve upon this boilerplate, so we’re gonna have to get a little bit creative. We got two options. Mess with balanceOf or mess with ownerOf. I argue that ownerOf is a necessary part of the ERC721 standard, as it is the only on-chain storage tying a tokenID to it’s owner’s address. However, balanceOf is a different story. When implementing ERC721Enumerable, the balanceOf call becomes incredibly useful, allowing a frontend to fetch a user’s inventory for example. The problem is, balanceOf alone cannot be used to derive any further information, not without the implementation of enumerability at least. Therefore, I propose that balanceOf should only be required in an ERC721 that implements ERC721Enumerable.
The tradeoff being made is that other contracts will not be able to retrieve a user’s NFT balance from the contract, but these contracts can still verify token ownership of a user if the contract is made aware of the users tokenID(s). One can argue a limitation would be an inability to write a contract that transfers the users first NFT on a given contract, although without implementing enumerability, this is not possible anyway.
Ultimately, this optimization doesn’t break compatibility, as tokens transferred will still emit proper events allowing marketplaces which index NFTs to catch all their transfers. Additionally the TokenURI will continue to work allowing these NFTs to point to images, videos, html, and whatever else the heart desires.
Let’s jump into our quite simple ERC721C _mint() implementation. Minting one NFT costs 29,828 units of gas.
function _mint(address to, uint256 id) internal virtual {
require(to != address(0), "INVALID_RECIPIENT");
require(ownerOf[id] == address(0), "ALREADY_MINTED");
ownerOf[id] = to;
emit Transfer(address(0), to, id);
}
As you can see, we do some basic checks, which we chose not to remove as you may need them, even if someone else’s contract may not. Then we update the owner of the token and emit the Transfer event. Now the user can interface with the token, just like they would almost any other ERC721.
One element to consider when implementing ERC721C is the goals of your NFT. When building large, NFT-centric communities, balanceOf may be useful to build token-gated access. Functional NFTs such as Uniswap LP positions on the other hand, would benefit greatly from the reduced gas costs, increasing accessibility of the protocol.

