Save Gas Fees on NFT using ERC721A Standard
Tags: programming, blockchain, productivity, tutorial
Published: 2022-12-22 13:54:07

In the past two years if you are into the crypto space then you've probably experienced the boom of NFT (Non-Fungible Token). The biggest problem it brings along with itself is the high gas price and network congestion in the Ethereum blockchain. The easiest solution is to use a Layer-2 or EVM compatible blockchain which supports smart contract, but as more big players in the industry like Yuga Labs (Creators of Bored Ape Yacht Club and Otherside) and Moonbirds are opting for Ethereum blockchain the gas problem has become worse day by day.

Smart Contract Developers at Sandbox, Cool Cats, and almost every other NFT startup have faced the same issue, many trying to optimize their smart contracts in their own way. Developers at Chiru Labs (Creators of Azuki) came up with the new ERC (Ethereum Request for Comment) standard for NFT called ERC721A to supersede the previous standard ERC721 which was proposed by the EIP (Ethereum Improvement Proposals).

## Let's understand the problem 🥀
If you aren’t familiar with the term "gas fee", it's a payment made by users to execute transactions on the Ethereum blockchain. The fee is paid in "ether", the cryptocurrency used on Ethereum, and is calculated based on demand for block space on the network. The amount of the fee is expressed in "gwei", which is 10^(-9) ETH. Gas fees are typically set automatically by a user's wallet.

During times of high demand for NFTs, such as when a popular NFT project releases new items, it can lead to a surge in the number of transactions being executed on the Ethereum blockchain. This can result in a phenomenon known as a "gas war", where the price of gas spikes significantly. This can have a negative impact on the user experience, as the high gas fees can make it more expensive to execute transactions on the network.

For example, the popularity of the Loot project led to a rush of users trying to mint and list Loot derivatives, which caused several spikes in gas fees and raised the price of transactions across the Ethereum network. The plots illustrate how the gas fees rose significantly whenever Loot derivatives were minted.


![Base Fee NFT Loot Derivated](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3o7nae36plkzip4g7il.png)

![Loot Derivatives Mint](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fml5fojhi230gwsrtbu2.png)

## Understanding the scale of the problem 📈
The Ethereum blockchain has relatively high gas fees compared to other blockchain networks, with the cost of executing a transaction ranging from a few dollars to over $500, depending on the complexity of the transaction and the level of demand on the network. This means if an NFT costs you $200, with the inflated gas prices you have to pay $700 ($200 + $500).

## What is ERC721A 🌹
ERC721A is a version of the IERC721 (I in IERC721 means Interface) standard that allows for more efficient creation of multiple NFTs in a single transaction, resulting in cost savings in terms of gas fees, potentially as much as 80% compared to other methods. The timeline of ERCs are:

```
ERC721 -> ERC721 OZ -> ERC721A
```

Additionally, this solution can help mitigate the network congestion that is commonly experienced on the Ethereum blockchain when creating NFTs, as it minimizes the amount of data required to be stored in the token metadata and updates the ownership state only once per batch of minting.

## A technical deep dive 🔬
ERC721A has introduced three optimizations in the previously used smart contract implementation developed by OpenZeppelin (OZ).

**1. Removing duplicate storage from OZ ERC721Enumerable**
The OZ implementation of the IERC721Enumerable standard, which is widely used, includes redundant storage of metadata for each individual token. This approach is optimized for read functions but can be costly in terms of gas fees for write functions, which are less commonly used and often require a higher fee to be executed. Additionally, the fact that the tokens are numbered sequentially in the new implementation from 0 allows for the removal of some redundant storage from the base implementation.

**2. Updating the owner’s balance once per batch mint request, instead of per minted NFT**
Suppose Alice currently owns 2 tokens and wants to purchase an additional 5 tokens. In the Solidity programming language, it costs gas to update stored values. Therefore, it would be more cost-effective to update Alice's token holdings from 2 to 7 in a single update, rather than performing 5 separate updates (from 2 to 3, 3 to 4, etc.) to track the addition of each individual token. This is because updating a stored value multiple times incurs additional gas costs, whereas updating the value in a single transaction only incurs the cost once.

**3. Updating the owner data once per batch mint request, instead of per minted NFT**
This optimization is similar to the previous one in that it aims to reduce the number of updates made to stored values in order to save on gas costs. In this example, Alice wants to purchase 3 tokens numbered 100, 101, and 102. Instead of updating the ownership information for each individual token (which would incur 3 separate gas costs), it would be more efficient to update the ownership information just once in a way that semantically indicates that Alice owns all 3 of these tokens. This would result in a single update rather than 3, reducing the total gas cost.

Suppose Alice and Bob are minting NFTs. Specifically, Alice is minting tokens numbered 100, 101, and 102, and Bob is minting tokens numbered 103 and 104. The internal owner tracker is a system for keeping track of the ownership of these NFTs, and in this case, it would look like this:

![Internal Tracker NFT Minting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0gfr9wmkx98y8es5khb.png)

The key point being made in this statement is that it is possible to determine the owner of an NFT without having to explicitly store the ownership information for that specific NFT. This can be done by modifying the "ownerOf" function to use a different method for determining the owner of the 102 NFT.

```solidity
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
  require(_exists(tokenId), "ERC721A: owner query for nonexistent token");

  uint256 lowestTokenToCheck;

  if(tokenId => maxBatchSize) {
    lowestTokenToCheck = tokenId - maxBatchSize + 1;
  }

  for(uint256 curr = tokenId; curr >= lowestTokenToCheck; curr--) {
    address owner = _owners[curr];
    if(owner != address(0)) {
        return owner;
    }
  }

  revert("ERC721A: unable to determine the owner of token");
}
```

An important thing to understand is that the function ownerOf will continue to operate correctly if we modify it to decrease the value until it locates a specifically designated owner.

Now let's see with an example on how we can mint an NFT using ERC721A.

First of all, initialize a Node project.

```bash
npm init -y
```

Install Hardhat (Ethereum Development Environment).

```bash
yarn add hardhat -D
```

Setup a Solidity project.

```bash
npx hardhat

> Create a TypeScript project
> Hardhat project root: if not provided then enter your current working directory
> Do you want to add a .gitignore? y
> Help us improve Hardhat with anonymous crash reports & basic usage data? y
> Do you want to install this sample projects dependencies with yarn (...)? y
```

This will initialize various elements in our project, including Hardhat's default settings with TypeScript support.

We now have a functional development environment, which includes a simple example contract called `Lock.sol` or `Greeter.sol`. However, this contract will not be useful for our purposes. Let's create a new file in the `contracts` folder called `BoredLion.sol`.

To utilize ERC721A, we simply need to install it. This package depends on another package provided by OZ, so it's a good idea to include it as well.

```bash
yarn add erc721a @openzeppelin/contracts -D
```

Finally, we can write the Solidity code inside the BoredLion.sol file, which allows us to `mint` our very own NFT called `BoredLion`.

```solidity
//SPDX-License-Identifier: MIT  
pragma solidity ^0.8.11;  
  
import "erc721a/contracts/ERC721A.sol";  
  
contract BoredLion is ERC721A {  
  constructor() ERC721A("Our Bored Lion", "BoredLion") {}  
  
  function mint(uint256 quantity) external payable {
    _safeMint(msg.sender, quantity);  
  }  
}
```

## Closing thoughts 🌺
ERC721A has a wide range of potential use cases and can offer significant cost savings in terms of gas fees. The purpose of this article was to introduce ERC721A and highlight its potential benefits for developers looking to create NFT on the Ethereum blockchain. Check out all the features in the [documentation](https://chiru-labs.github.io/ERC721A). In case you have some questions regarding the article just leave a comment or want to discuss something feel free to connect with me on [LinkedIn](https://www.linkedin.com/in/musabshakil/).

_Special thanks to [TokenMinds](https://tokenminds.co/), [CoinsBench](https://coinsbench.com/) and [nft now](https://nftnow.com/)_

> If you work at a web3 startup and want me to write for your product please do connect with me 🍀