ERC721 how to set unique ipfs CID per minted token

Hey
I'm trying to understand smart contract development by developing a nft minting contract.

It's going pretty well. I've made a contract that can mint nft's, and a test frontend where users can press a mint button, which calls a mint function in the contract. That all works well.

The trouble is that I want each token to link to a different json uri, and I need to create them (and upload them to ipfs) before the minting starts. The software I'm using is not capable of producing the images on-chain.

My question is this: What would be the best way to connect each token with each json file? It's not difficult for me to make a json file with an array of all the ipfs CID's, but I have a hard time figuring out how to get them "into the contract". If I send one of them (selected by mint total count) together with the mint() call from the frontend, I risk sending two identical CID's, before the token gets minted and mint count is updated. I don't think I should keep a list of all the CID's in the contract, that would take a lot of space. So what then? How do people normally solve this?

Thanks in advance :slight_smile:

I'm looking a bit at the Events in solidity. It seems like a possibility to have the contract emit an event upon minting and listen for it in the frontend and then use the event id to create the metadata (if not already created) using a setURI() call.

It does seem a bit overkill to do it this way though.

I guess its also a possibility to store an array of id's mapped to hashes in the contract, and update it externally through a function call before the minting starts. But that would probably be a pretty pricey call.

There's also this technique described here: How to: ERC-1155 ID Substitution for Token URI - #6 by wighawag
But at the moment I'm using Pinata to upload the files, so I'm not sure i can add them into directories from there.

ok, I'm pretty sure I getting closer to my solution.
This thread seems to describe what I want: Why doesn't OpenZeppelin ERC721 contain setTokenURI? - #4 by frangio

1 Like

Right! You should be able to follow the approach described in that thread. Pinata allows you to upload the directory with your images, and will give you the IPFS link to use as baseURI.

Let us know how it goes!

1 Like

@frangio @asger
This exchange has been very helpful.

Like Asger, I'm writing a mint-on-demand 1k collection of nfts. If I upload all images to IPFS (and pin them), wouldn't users be able to see all the images before they're minted via the solidity contract? This would ruin the "reveal" at minting wouldn't it?

I could probably create the folder (and a handful of images for a pre-mint/airdrop/giveaway), then my react webapp could upload the image when a user hits mint. (I thought each nft file would have it's own CID, but I guess each image builds a uri off the CID).

Though it would be nice to upload them all at once.

Thoughts on best practice here?

I feel that the reveal is more about the randomness of what you will get when you mint, and having access to all of the images beforehand doesn't ruin that part of the reveal. That said, I'm not very familiar with the culture around this so consider this an uninformed opinion.

Agreed, though it's not truly random, since they're minted sequentially using:

    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

and

   _tokenIds.increment();

The only "randomness" is introduced by other users minting tokens. If the mint activity is high, then it's more random, because we're not sure how many tokens will be minted before yours, but if it's low activity, the minter could determine which of the sequential tokenId's images are "up next." And, ultimately, see where the rarest nft's are in that order (and if they've already been minted).

But maybe I'm over thinking it. Maybe no one would really game the minting process this way?

If there was a low-cost, gas-efficient library to randomize the counters, that would be ideal here. For example, the Counters library, but RandomizedCounter where you set the max number in the counter, and the counter doles out the indexes randomly. Know of any libraries like that out there or thoughts on writing it (with gas costs and optimization in mind)?

You should absolutely assume that people will try to game the minting process.

Randomness on the blockchain is difficult. I don't know the state of the art for this. You can try to search around this forum for recommendations. You should also try to learn from other notable NFTs.

MultiRaffle is an example of an implementation, you can see how it does randomness.