Skip to article content

Azuki and ERC721A

updated

Azuki's team developed ERC721A for its January 12, 2022 NFT sale. The implementation reduces repeated ownership storage writes when sequential NFTs go to one recipient. Ordinary minting still emits an event per token, so larger batches continue to add execution costs.

Token Interface
ERC-721, including the metadata extension.
Contract Version
ERC721A Contracts v4.3.0.

Shared Ownership Storage

ERC721A v4.3.0's ordinary mint function initializes ownership at a sequential batch's first token ID. That entry packs the recipient address, timestamp and ownership flags into one storage value. The function also updates the recipient's balance and minted count together in a packed account record.

The remaining token IDs can share that initial ownership information without separate entries at mint time. For an existing sequential token without its own initialized entry, ownerOf searches backward to find the applicable record. Each NFT still has its own token ID.

A batch spreads those shared storage updates across its NFTs. Separate mint calls each initialize their own starting ownership entry. The ordinary _mint path still loops through every token to emit a Transfer event. Fewer ownership writes therefore reduce one part of the cost without making total gas use constant.


Ownership Lookups and Transfers

An ownerOf lookup may scan several entries when a token sits far from its batch's initialized record. The contract comments describe the initial lookup cost as proportional to the maximum mint batch size. Later transfers initialize more ownership entries, which can shorten subsequent searches.

A transferFrom call writes an explicit ownership entry for the token that moves. When the next token already exists and lacks an initialized entry, the function copies the previous ownership record there. That neighboring NFT keeps its existing owner.


Minting Paths and Receiver Checks

The internal functions _mint , _safeMint and _mintERC2309 require a nonzero recipient and a quantity greater than zero.

  • _mint emits a Transfer event for each token. It does not call onERC721Received to check whether a contract recipient accepts the NFTs.
  • _safeMint uses the ordinary mint logic and adds receiver checks when the recipient has contract code. It calls onERC721Received for every token. Each callback must return the expected selector, or the mint reverts.
  • _mintERC2309 emits one ConsecutiveTransfer event for the batch. Its ERC-721-compliant use applies only during contract creation. Version 4.3.0 limits this helper to 5,000 tokens per call.
Illustration: Azuki: Minting Paths and Receiver Checks

View full-size image

Receiver callbacks add work beyond the shared ownership updates, so the chosen minting path affects gas use. The creation-only ERC-2309 helper has different event handling from an ordinary public mint.

The _mintSpot function handles individual non-sequential token IDs above the _sequentialUpTo() boundary in v4.3.0. Its default boundary leaves no available spot range; a derived contract must override it to enable that path. Each spot mint initializes its own ownership entry, separately from the sequential batch mechanism.


Collection Integration

ERC721A supplies internal helpers, while the collection contract defines its public mint entry point. The second argument in _mint(to, quantity) specifies how many tokens to create for that recipient. The README's minimal example forwards that count without enforcing payment, allowlist eligibility or a collection supply cap.

Minting Checklist

  • If the recipient has contract code, include the per-token receiver callbacks when assessing _safeMint 's cost.
  • If minting occurs after contract creation, exclude _mintERC2309 to preserve ERC-721 compliance.
  • When migrating to version 4.x with OpenZeppelin extensions, review supportsInterface compatibility, especially for ERC2981 integrations.
  • If a sale requires payment or restricts eligibility or supply, implement those checks around the internal mint call.