ERC721A an Improved ERC721 Implementation

ERC721A is an improved implementation of the IERC721 standard that supports minting multiple tokens for close to the cost of one.

Thu Apr 28 2022

ERC721A an Improved ERC721 Implementation

ERC721A is an improved implementation of the IERC721 standard that supports minting multiple tokens for close to the cost of one.

A word about ERC-721

ERC-721 is most likely the widely used token standard after ERC-20. ERC-721 is the standard used in NFT contracts and other NFT Marketplaces

Built on top of the Ethereum blockchain, the first real iteration of a non-fungible standard came about with ERC721. It was popularized in late 2017 with the rapid adoption of CryptoKitties, a game which allowed for the purchase, and subsequent ‘breeding’ of digital cats.

Why people seek for a different standard when ERC-721 is more usable and widely accepted? Because we needed something which is more gas optimized when we mint multiple NFTs at once?

IERC721 TLDR

  • ERC721A is an implementation of IERC721 with significant gas savings for minting multiple NFTs in a single transaction.
  • The Azuki contract will enable minting multiple NFTs for essentially the same cost of minting a single NFT.
  • We partnered with an external security consultant to ensure our approach is sound.
  • We encourage the broader community to adopt this implementation to save gas costs for their users.

We’ve measured the gas costs and prices for minting, comparing OpenZeppelin’s ERC721Enumerable vs ERC721A. In our measurements, the same application-level logic is used, the only difference being the safeMint function called.

IERC721 gas estimate

IERC 721 Optimizations

So how can we optimize this gas price? To achieve this we need 3 different optimizations to get this working. ERC721A

Optimization 1 - Removing duplicate storage from OpenZeppelin’s (OZ) ERC721Enumerable

The widely-used OZ implementation of IERC721Enumerable includes redundant storage of each token’s metadata. This denormalized approach optimizes for read functions at a significant cost to write functions, which isn’t ideal given that users are much less likely to pay for read functions. Additionally, the fact that our tokens are serially numbered starting from 0 lets us remove some redundant storage from the base implementation.

Optimization 2 - updating the owner’s balance once per batch mint request, instead of per minted NFT

Suppose Alice has 2 tokens and wants to buy 5 more. In Solidity, it costs gas to update a stored value. Therefore, if we are tracking in storage how many tokens Alice owns, it would be cheaper to update Alice’s holdings from 2 directly to 7 with one update, instead of updating that value 5 times (once per additional token, from 2 to 3, 3 to 4, etc).

Optimization 3 - updating the owner data once per batch mint request, instead of per minted NFT

This is similar in spirit to optimization 2. Suppose Alice wanted to buy 3 tokens - token #100, #101, and #102. Instead of saving Alice as the owner 3 times (each time costing us gas), we can instead save the owner value just once in a way that semantically implies that Alice owns all 3 of those tokens.

/**
 * @dev See {IERC721-ownerOf}.
 */
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
    address owner = _owners[tokenId];
    require(owner != address(0), "ERC721: owner query for nonexistent token");
    return owner;
}
Leave a comment

To make a comment, please send an e-mail using the button below. Your e-mail address won't be shared and will be deleted from our records after the comment is published. If you don't want your real name to be credited alongside your comment, please specify the name you would like to use. If you would like your name to link to a specific URL, please share that as well. Thank you.

Comment via email
Nikhil M
Nikhil M

Entrepreneur / Privacy Freak / Humanist / Blockchain / Ethereum / Elixir / Digital Security / Online Privacy

Tags Recent Blogs