I'm creating a version 2 of a NFT collection with 1025 unique nfts, collection 1 also had 1025 unique nfts. The minting is split up in three phases.
- Mint for holders, where they get their unique corresponding version 2 NFT. The idea here is that if you for instance had tokenID 26 in version 1, you will mint version 2 tokenID 26 as well. If there are any NFTs left, i.e not all holders of version 1 minted their version 2. Then we move on to phase 2.
- Whitelist, get to mint the potential remainding nfts that have not been minted by the holders of v1 for a reduced price.
- Public, get to mint the potential remainding nfts for full price.
I know the setup is a bit weird, but don't worry about that. The problem:
How to know which tokenIDs are valid for whitelist and public sale i.e which tokenIDs were not minted by the holders. We have tried having an uint256[] public unmintedTokens array, that we initilize with all 1025, and then remove when NFTs are minted. This required to many for loops both in the constructor:
constructor(address version1NFTAddress) ERC721("Version2NFT", "V2NFT") {
version1NFT = IVersion1NFT(version1NFTAddress);
for (uint256 i = 1; i <= MAX_NFT_SUPPLY; i++) {
unmintedTokens.push(i);
}
}
And in the mint function to remove the minted token id:
for (uint256 i = 0; i < unmintedTokens.length; i++) {
if (unmintedTokens[i] == version1TokenId) {
unmintedTokens[i] = unmintedTokens[unmintedTokens.length - 1];
unmintedTokens.pop();
break;
}
}
We did some calculations and this required way too much gas.
Solution 2: Have a mapping uint256 => bool to see if tokenID has been minted or not. And then in the public/whitelist mint function finding a tokenID that has not been minted:
mapping(uint256 => bool) public mintedTokens;
uint256 public nextPublicTokenId = 1;
function publicMint() public {
require(nextPublicTokenId <= MAX_NFT_SUPPLY, "All tokens have been minted");
while (mintedTokens[nextPublicTokenId]) {
nextPublicTokenId++;
require(nextPublicTokenId <= MAX_NFT_SUPPLY, "All tokens have been minted");
}
_safeMint(msg.sender, nextPublicTokenId);
mintedTokens[nextPublicTokenId] = true;
nextPublicTokenId++;
}
This also required way too much gas. Does anyone have any ideas that are still onchain or do we have to go offchain? We hope to keep the holders minting setup, that if you have tokenID 4 in version 1 you get tokenID 4 in version 2. We want it this way to easily publish the corresponding metadata and unique art. All help appreciated :)