🎨 How to Deploy an ERC721 NFT Factory Contract with IPFS Metadata
🛠 Step 1: Use the Correct Smart Contract Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import “@openzeppelin/contracts/security/ReentrancyGuard.sol”;
import “@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol”;
import “@openzeppelin/contracts/access/Ownable.sol”;
/**
- @title IvanovNftFactory
- @notice A secure ERC721 NFT factory that cycles through a preset list of URIs.
*/
contract IvanovNftFactory is ERC721URIStorage, Ownable, ReentrancyGuard {
uint256 public tokenCounter;
mapping(address => bool) public additionalOwners;
string[] public uriList;
uint256 public currentURIIndex; event NFTMinted(address indexed to, uint256 tokenId, string tokenURI); constructor(string[] memory initialUris)
ERC721(“CharlyNFT”, “TNFT1”)
Ownable(msg.sender)
{
require(initialUris.length > 0, “CharlyNft: need at least one URI”);
tokenCounter = 0;
for (uint256 i = 0; i < initialUris.length; i++) {
uriList.push(initialUris[i]);
}
currentURIIndex = 0;
} function updateURIList(string[] memory newUris) external onlyOwner {
require(newUris.length > 0, “CharlyNft: need at least one URI”);
delete uriList;
for (uint256 i = 0; i < newUris.length; i++) {
uriList.push(newUris[i]);
}
currentURIIndex = 0;
} function addUri(string calldata newUri) external onlyOwner {
uriList.push(newUri);
} function addUris(string[] calldata newUris) external onlyOwner {
for (uint256 i = 0; i < newUris.length; i++) {
uriList.push(newUris[i]);
}
} function mintNFT(address to, string memory tokenURI)
external
onlyOwner
nonReentrant
returns (uint256)
{
uint256 tokenId = tokenCounter;
_safeMint(to, tokenId);
_setTokenURI(tokenId, tokenURI);
tokenCounter += 1;
emit NFTMinted(to, tokenId, tokenURI);
return tokenId;
} function addOwner(address newOwner) external onlyOwner {
additionalOwners[newOwner] = true;
} modifier onlyOwners() {
require(
owner() == msg.sender || additionalOwners[msg.sender],
“CharlyNft: not authorized”
);
_;
} function mintExactNFT(address to)
external
nonReentrant
onlyOwners
returns (uint256)
{
require(uriList.length > 0, “CharlyNft: no URIs available”);uint256 tokenId = tokenCounter; string memory uri = uriList[currentURIIndex]; _safeMint(to, tokenId); _setTokenURI(tokenId, uri); emit NFTMinted(to, tokenId, uri); tokenCounter += 1; currentURIIndex = (currentURIIndex + 1) % uriList.length; return tokenId;}
}
🧩 Step 2: Prepare Your Image Files
Create a folder and add all your 512x512 or 1024x1024 images.
Rename them cleanly to charly1.png, charly2.png, etc.
🖥 Rename in Ubuntu:
a=1; for f in *.png; do mv “$f” “charly${a}.png”; ((a++)); done
📌 This assumes all files are .png. Change the extension if needed.
📤 Step 3: Upload to IPFS (via Pinata)
Go to https://app.pinata.cloud
Upload the folder with all renamed images
You’ll receive a CID like:
bafybeibtxyt5gwhbywi6z6y6gdqach4bxoq62yp7kl24mvkrlc6ii54zte
Now your images live at:
ipfs://bafy…/charly1.png
ipfs://bafy…/charly2.png
📄 Step 4: Generate Metadata JSON Files
Create a file called generateMetadata.js:
const fs = require(“fs”);
const path = require(“path”);
const imageCID = “bafybeibtxyt5gwhbywi6z6y6gdqach4bxoq62yp7kl24mvkrlc6ii54zte”;
const total = 58;
const outputDir = “./metadata”;
if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir);
for (let i = 1; i <= total; i++) {
const metadata = {
name: Charly NFT #${i},
description: “Part of the official Charly NFT collection”,
image: ipfs://${imageCID}/charly${i}.png,
attributes: [
{ trait_type: “Breed”, value: “White Swiss Shepherd” },
{ trait_type: “Generation”, value: “Genesis” },
{ trait_type: “Edition”, value: ${i} }
]
};
fs.writeFileSync(
path.join(outputDir, ${i}.json),
JSON.stringify(metadata, null, 2)
);
}
console.log(✅ Done. Metadata written to ${outputDir}/);
Then run it:
npm init -y
node generateMetadata.js
📤 Step 5: Upload Metadata to IPFS
Upload the entire /metadata folder to Pinata
You’ll get a CID like:
bafybeihm5albdxvs5xosbfuczd5hbqi72apyrxpyttt4bkjymtdm5tgrge
Now your URIs are:
ipfs://bafy…/1.json
ipfs://bafy…/2.json
…
ipfs://bafy…/58.json
🚀 Step 6: Deploy Your Contract
Use Remix:
In the constructor, paste:
[
“ipfs://bafy…/1.json”,
“ipfs://bafy…/2.json”,
“ipfs://bafy…/3.json”
// … up to 58
]
If Remix slows down, split into chunks and use the addUris() function.
🐶 Step 7: Mint the NFTs!
Use mintExactNFT(to) to mint NFTs one by one using the next URI in the cycle.
It’ll start from 1.json, then 2.json, then wrap around.
💡 Pro Tip: Use AI to generate your full URI array if you don’t want to write it manually. Just provide:
Your IPFS metadata CID
The number of files
Example output:
[
“ipfs://bafy…/1.json”,
“ipfs://bafy…/2.json”,
…
“ipfs://bafy…/58.json”
]
You’re done! 🎉 You now have a full ERC721 NFT factory setup ready for production or testnet.
Let me know if you’d like me to turn this into a PDF, Markdown, or help embed it in a custom webpage for your project.
ChatGPT can make mistakes. Check important info.
https://testnet.bscscan.com/address/0x57F750337032B09155964d24b818bF374fd83907