How the Right Implementation of ERC721 Brings Additional Utility to Your NFT

NFTs started out by disrupting the art world, with artists constantly striving to create and showcase the craziest and out-of-the-box art pieces. We’ve seen the battle between pixels, generative or real-life art transformed into a collection of NFT projects. 

Nowadays, NFTs are no longer a simple buzz in the digital art community. They’ve created a realm of collaborations between artists and crypto-billionaires. Yet, apart from being outstanding and unique, the NFT art collection also needed to have some utility. This concept of utility translated into whitelist, early access or exclusive access to Alpha projects, offline events, or On-Chain games. 

Then, a new problem set in, and that was running out of gas when minting NFTs. But there are ways to optimize the bytecode and thus minimize gas consumption.

Read below the helpful pointers. 

Iterate Owned Tokens with tokenOfOwnerByIndex function

At Softbinator, we’ve helped NFT creators migrate their OpenSea (the first and largest marketplace for NFTs) collections into custom NFT contracts. These contracts can be used as proof of ownership and later as a utility – the best perk when owning an NFT, giving access to unique experiences. The problem with smart contracts is that they cost more gas than they normally should if not optimized properly. Both creators and users of smart contracts can be overcharged.  

Everyone started to look into implementing ERC721Enumerable in order to expand the normal ERC721 functionality.

By default, ERC721, as it’s specified in the EIP-721 (yes, this is the NFT standard from Ethereum’s Improvement Proposal from where ERC721 got its name) doesn’t have a way to retrieve all the tokens held by an owner. That’s why the extension called ERC721Enumerable came up with an excellent method to solve this problem: tokenOfOwnerByIndex.

Here is what tokenOfOwnerByIndex does: it lets you retrieve a certain token ID owned by a wallet, by using an index.  Knowing the IDs is essential as the tokens can have specific traits that can be used later as a “utility”. 

But tokenOfOwnerByIndex() is still a bit chunky, as you have to: 

  • call first balanceOf() to get the total tokens owned by a holder; 
  • call tokenOfOwnerByIndex() for all every token.  

Since this process happens offline, it might cause some issues in terms of UX; as you know, RPCs sometimes don’t like to be bothered with requests. 

A solution to this is creating your own view function tokensOfOwner(), tokensOfWallet(), or whatever you want to call it, so you can iterate via one call through all the owner’s tokens and return the IDs. 

And this is the typical out-of-gas use case. When a wallet has many IDs, this view can run out of gas.   

Best ERC721 Implementation for Gas Efficiency

Inspired by WINTΞR‘s tweet, here’s an overview of different implementations of Enumerable and which one is more gas efficient.

We’ll use 3 out of 4 ERC721 implementations:

• @OpenZeppelin

• @transmissions11’s solmate

• @AzukiOfficial’s ERC721A

The test data will be a contract with 10k tokens and an owner with random 5k tokens.

OpenZeppelin

The most notorious library implemented by the OZ team: ERC721Enumerable analysis. 

Implementation

As you can see, the OZ implementation is keeping an array of addresses and their index and an additional 2 mappings as well as an array for the easiness of enumeration.

The gas consumed by this implementation at minting is an average of 145802 and at iterating through 2.5k is 2993628.

Azuki 

As the tweet stated, Azuki is more optimized for batch minting and, in our tests, we minted one by one so, meaning that the minting gas is not so relevant. That said, the iteration part is really bad, and we had to decrease to 1k tokens because it ran out of gas for 10k tokens.

The mint average is 56683 and iterating through 2.5k is 2993628.

Solmate

Solmate is a modern, minimalist, and gas-efficient ERC721 implementation from the Rari-Capital team (written by transmissions11, a well-known solidity dev). Solmate is mostly doing unchecked increases of balance. It most often follows OpenZeppelin patterns but with fewer checks.

Solmate seems to be pretty optimized, minting is 51491 and iterating 72477.

Check the rundown of the gas benchmark for each implementation:

You can check our reference implementation of the ERC-721 on GitHub.

Key Takeaways About Adding NFT Utility

So, if you want to add NFT utility to your collection, you have to plan that from the beginning and choose the right implementation of ERC721. Minting can be cheap for different implementations, but later, you will have big problems with expanding the functionality.

Some NFT projects already face this issue, and they have to rely on tools like The Graph to index the token’s holders and create utility off-chain.