So I'm working on an NFT project that will eventually create a collection of approximately 3000 different unique NFTs. Kind of like cryptopunks.
Besides the ERC-721 contract, there will also be a server hosting a website where people will be able to go to mint said nft, as well as having the logic to generate the nft itself.
The issue I'm facing now is: how exactly can I guarantee the image will be 100% unique given 3000 or so possible combinations? I'm not quite sure if the information on the already-minted NFTs should be held serverside or in the ERC-721 contract itself. Having the information on the contract does seem to make more sense, but wouldn't that be a bit heavy? That would mean that whenever interacted with, the contract would know which NFT attributes have already been used for minting and would avoid minting a new one with any of those.
Is this the best way to approach it? Am I missing a best-practice?


2 Answers 2


There's a few ways to do it that I've seen.

  1. Use attributes

All the attributes are stored succinctly into one variable of 256 bits. If you can create a repeatable process to create an image from attributes and you can guarantee that every different valid input creates a separate image then you're good. It is trivial for the smart contract to validate non-duplication. (See CryptoKitties)

  1. Precalculate

You can precalculate all possible images. Then as tokens are minted the guaranteed-unique image is available. The entire set can be committed up-front, even if not publicly known. (Related to CryptoPunks)

  1. Trust

As new tokens are minted they do not have any image at all. Then, asynchronously, you will create and publish those images. The smart contract does zero validation here and people must trust you.

  • Super detailed answer, thank you. Yes I'm considering using a sort of precalculation for this particular project. Using attributes would make the most sense and honestly would be the easiest approach, but the issue with that would be guaranteeing said attributes were unique (since that would have to be done during the minting process on the contract directly, and would probably increase gas costs by a lot).
    – Ress
    Commented Aug 16, 2021 at 14:50
  • If you're creative (and lucky as to the problem space) you can find a mapping which is surjective from the attributes to the token ID. This makes gas cost O(1). Commented Aug 16, 2021 at 23:52
  • Quick note on the precalculate: even if committed up-front, is there a way to implement a precalculation in such a way that is avoids concurrency issues? I'm picturing something like a json file with all the possible combinations, but upon minting a combination I would have to guarantee that it can no longer be used, correct? Could I just store the already-made combinations in the contract itself as a guarantee?
    – Ress
    Commented Aug 17, 2021 at 18:37
  • All of these are possible. And can be done in O(1), or in other words "cheaply". Commented Aug 17, 2021 at 20:25

I guess the attributes you are talking about are in the ERC721 metadata. And that metadata is stored somewhere (maybe in IPFS?).

What I would suggest is that you store the used attributes in your centralized server. So whenever someone mints something, you store that information. And your website simply checks the database to make sure that another NFT can't be minted with the same attributes.

This way the same attributes can be used if someone uses the contracts directly, without your UI. If you want to prevent also this, then you need to store the used attributes in the contracts on-chain in some data structure. In the minting functionality you'll then do the similar check.

  • So let's say someone interacts with the contract and mints an nft. How would I be able to set the picture and json with the properties afterwards? Do I need to call an endpoint in my server from the contract itself that will request the information based on the contract's properties? Is that possible / a good practice?
    – Ress
    Commented Aug 10, 2021 at 9:57
  • It depends on your implementation, so you can decide how it should be done. OpenZeppelin, by default, creates the tokenURI automatically based on the ID: github.com/OpenZeppelin/openzeppelin-contracts/blob/… Commented Aug 10, 2021 at 10:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.