Skip to main content

🎥 How to Create an NFT Collection with AI, IPFS, and Foundry

Updated on
Sep 4, 2024

16 min read

Overview

Non-fungible tokens (NFTs) have seen a surge in popularity, gaining adoption from the worlds biggest brands. While previously, it was necessary to have a background in art or design to generate your NFT images, we're going to show you how to leverage generative AI to fast-track the launch of your collection.

In this guide, we will be using:

  • OpenAI API to generate the images
  • IPFS to store the images and metadata
  • OpenZeppelin's audited ERC-721 NFT smart contract
  • Foundry to deploy the smart contract and mint the NFTs
  • QuickNode's best-in-class RPC service to power the entire process
Prefer a video walkthrough? Follow along with our friend EatTheBlocks and learn how to create an NFT collection using generative AI and QuickNode's IPFS.
Subscribe to our YouTube channel for more videos!

You can check out the reference repository here, or follow along in our detailed guide below.

Part 1 - Generate NFT Images, Metadata, and Upload to IPFS

Step 1 - Create Project and Install Dependencies

npm i -S axios dotenv

Step 2 - Configure Environment Variables

We'll need an OpenAI API Key (also referred to as a secret key) and a QuickNode API key we'll use in subsequent steps. Create a new .env file in the root of your project and add the following values:

.env
OPENAI_API_KEY=your-openai-api-key
QUICKNODE_API_KEY=your-quicknode-api-key

Follow the steps outlined by OpenAI for generating your key. To use this key, you will have to load a small amount of funds onto your OpenAI account. Each time you run the code from this guide, it will cost about $0.10. If you're looking to complete the tutorial free of charge, you can enter the prompts manually into the ChatGPT UI instead.

We'll cover the QuickNode API key later.

Step 3 - Generate Images

To generate our images using the OpenAI API, we'll be using the following code. If you'd like to learn more about how to use this API, you can check out the OpenAI API docs. We'll be using the Create Image endpoint to retrieve a base 64 encoded json making it easy to save to our filesystem.

Keep in mind their rate limits if you're looking to generate a large number of images.

Create the generate-images.js file and paste the below code.

generate-images.js
require('dotenv').config();
const axios = require('axios');
const fs = require('fs');

const generateImage = async (prompt) => {
try {
const response = await axios.post(
'https://api.openai.com/v1/images/generations',
{
prompt: prompt,
n: 5, // Number of images to generate
size: "1024x1024", // Size of the image
response_format: "b64_json" // Returns the file itself, encoded as base64 JSON, this way we can directly save it
},
{
headers: {
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json'
}
}
);

return response.data;
} catch (error) {
console.error("Error generating image:", error);
return null;
}
};

const saveImage = (imageData, index) => {
const buffer = Buffer.from(imageData, 'base64');
fs.writeFileSync(`./image_${index}.png`, buffer);
};

const main = async () => {
const imageData = await generateImage("Cool pixel art NFT with a cyberpunk theme");
for (let i = 0; i < 5; i++) {
if (imageData) {
saveImage(imageData.data[i].b64_json, i);
}
}
};

main();

If you're looking for a style other than our cyberpunk pixel art, you can update the prompt we're passing into generateImage() on Line 36. If not, you can go ahead and execute the above code to generate our images.

node generate-images.js

Feel free to check out the image files you'll be using for your NFTs!

Step 4 - Generate Metadata, Upload, and Pin to IPFS

Next, we'll need to generate the NFT metadata and upload the files to IPFS. We will be "pinning" the files to ensure they remain available indefinitely. But first, we need to connect to an IPFS node.

tip

To use IPFS on QuickNode, a Starter plan or higher is required. View our pricing plans here.

Once your account is on a paid plan with access to IPFS, you will generate an API key. To generate an API key for your QuickNode account, you can follow the directions here. Be sure to configure the key with access to IPFS_REST.

Update the .env file we created in step 2 with your key.

Now that you have access to IPFS, we can move on to the fun part.

To generate the NFT metadata and upload/pin to IPFS using your QuickNode account, we'll be using the following code. This code is slightly different from the video in that it leverages our already installed axios library as opposed to the deprecated request-promise library. Create the upload-images.js file and paste the below code.

upload-images.js
require('dotenv').config();
const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');

async function uploadToIPFS(filePath, fileName, contentType) {
try {
const formData = new FormData();
formData.append('Body', fs.createReadStream(filePath));
formData.append('Key', fileName);
formData.append('ContentType', contentType);

const response = await axios.post(
'https://api.quicknode.com/ipfs/rest/v1/s3/put-object',
formData,
{
headers: {
...formData.getHeaders(),
'x-api-key': `${process.env.QUICKNODE_API_KEY}`,
},
}
);
return response.data;
} catch (error) {
console.error('Error uploading to IPFS:', error);
throw error;
}
}

function createNFTMetadata(filePath, imageUrl) {
const name = 'NFT name';
const description = 'NFT description';
const metadata = {
name,
description,
image: imageUrl,
attributes: [] // Add any additional attributes here
};
fs.writeFileSync(filePath, JSON.stringify(metadata));
}

async function main() {
try {
for (let i = 0; i < 5; i++) {
const imageName = `image_${i}.png`;
const imagePath = `./${imageName}`;

// Upload image
const imageUploadResponse = await uploadToIPFS(
imagePath,
imageName,
'image/png'
);
console.log('Image uploaded:', imageUploadResponse);

// Create metadata
const imageUrl = `https://quicknode.quicknode-ipfs.com/ipfs/${imageUploadResponse.pin.cid}`;
const metadataFile = `metadata_${i}.json`;
const metadataPath = `./${metadataFile}`;
createNFTMetadata(metadataPath, imageUrl);

// Upload metadata
const metadataUploadResponse = await uploadToIPFS(
metadataPath,
metadataFile,
'application/json'
);
console.log('Metadata uploaded:', metadataUploadResponse);
}
} catch (error) {
console.error('Error:', error);
}
}

main();

You can adjust the attributes value further if you would like a more production-ready collection.

To execute this code, we'll run the following command in the terminal:

node upload-images.js

Confirm your files are available on IPFS by grabbing the CID and adding it to the end of this URL: https://quicknode.quicknode-ipfs.com/ipfs/ENTER-CID-HERE

Important! Save the CIDs for your metadata files. We are going to need these later in Part 2, Step 6.

Now that our files are uploaded, we're ready to deploy our contract and mint our NFTs!

Part 2 - Deploy Contract and Mint NFTs

Step 1 - Initialize Foundry Project

Foundry is a robust toolkit for EVM development, we will be using it to deploy our smart contract. If you want to learn more about Foundry, you can check out our Introduction to Foundry guide.

If you don't yet have Foundry installed, you can install it using the following command in your terminal.

curl -L https://foundry.paradigm.xyz | bash

Now, in our root directory, we will initialize a Foundry project in a new, nft folder. We will do so with the following terminal command:

forge init nft

Update your configuration file adding our Solidity version.

foundry.toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.23"

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

Lastly, you'll want to delete three files with the word Counter in them. You'll find them in the nft/test/, nft/src/, and nft/script/ folders.

Step 2 - Write NFT Smart Contract

Here we will be leveraging the OpenZepplin ERC-721 contract. We'll first need to import them using the following terminal command:

git submodule add https://github.com/OpenZeppelin/openzeppelin-contracts lib/openzeppelin-contracts

Then, we'll create our contract code. Create the NFT.sol file in your nft/src/ directory, and paste the following code:

nft/src/NFT.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.23;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract NFT is ERC721, ERC721URIStorage, Ownable {
constructor(address initialOwner)
ERC721("MyToken", "MTK")
Ownable(initialOwner)
{}

function safeMint(address to, uint256 tokenId, string memory uri)
public
onlyOwner
{
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}

// The following functions are overrides required by Solidity.

function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}

function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}

Step 3 - Create an Address to Deploy From

First, we'll need to generate an address. For this guide, we'll use the simple web interface at vanity-eth.tk, but if security is a concern for you, you should check out our guides on How to Create and Ethereum Address using JavaScript, Go, PHP, Python, or Ruby.

Then, you're going to create a new .env file in your nft/ directory.

nft/.env
PRIVATE_KEY=0xyour-private-key
OWNER=your-address
TESTNET_RPC_URL=your-rpc-url

Add your private key (make sure you leave the 0x before it) and your address (also with the 0x prefix) to the owner variable. We'll get to your RPC URL later.

Step 4 - Get TestNet Tokens

In order to deploy a smart contract and mint our NFTs, we're going to need to pay transaction fees. On the testnet, this is done with testnet tokens, which you can get for free at: https://faucet.quicknode.com/ethereum/sepolia

Make sure you're logged into your QuickNode account while using the faucet to get extra tokens and lift some restrictions.

Just enter the address you generated in step 3 above.

Step 5 - Get RPC URL

While you can certainly run your own Ethereum node (check out our guide here), you can get access to a free endpoint on QuickNode. Simply create an account if you don't have one, go to endpoints at the left, and create an endpoint on Ethereum Sepolia.

Once you've created your endpoint, copy the "HTTP Provider" endpoint URL and add it to the .env we created in step 3 above.

Step 6 - Script Contract Deployment (and Minting)

Now we're going to tell Foundry how to deploy our contract. To streamlne things, we'll also tell it to mint our NFTs as part of the process.

Create the NFT.sol file in your nft/script/ directory, and paste the following code:

nft/script/NFT.s.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.23;

import {Script} from "forge-std/Script.sol";
import {NFT} from "../src/NFT.sol";

contract NFTScript is Script {
function setUp() public {}

function run() public {
vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
NFT nft = new NFT(vm.envAddress("OWNER"));

nft.safeMint(
vm.envAddress("OWNER"),
0,
"https://quicknode.quicknode-ipfs.com/ipfs/cid-of-metadata_0-file"
);
nft.safeMint(
vm.envAddress("OWNER"),
1,
"https://quicknode.quicknode-ipfs.com/ipfs/cid-of-metadata_1-file"
);
nft.safeMint(
vm.envAddress("OWNER"),
2,
https://quicknode.quicknode-ipfs.com/ipfs/cid-of-metadata_2-file"
);
nft.safeMint(
vm.envAddress("OWNER"),
3,
"https://quicknode.quicknode-ipfs.com/ipfs/cid-of-metadata_3-file"
);
nft.safeMint(
vm.envAddress("OWNER"),
4,
"https://quicknode.quicknode-ipfs.com/ipfs/cid-of-metadata_4-file"
);

vm.stopBroadcast();
}
}

Update the IPFS URLs in your file with the CIDs we saved from Part 1, Step 4.

Step 7 - Deploy Contract and Mint NFTs

Now in your terminal, you're going to navigate to the nft/ directory.

cd nft/

Load your environment variables.

source .env

And lastly, run the Foundry command for deployment.

forge script script/NFT.s.sol:NFTScript --rpc-url $TESTNET_RPC_URL --broadcast 

You should see a line that says:

✅  [Success]Hash: [a transaction hash]

Grab that transaction hash, and search for it at https://sepolia.etherscan.io.

Wrap Up

Congratulations! You've deployed an ERC-721 smart contract and minted 5 NFTs with the help of generative AI. If you are building something similar or have questions about this guide, feel free to reach out to us on Discord or Twitter.

We ❤️ Feedback!

Let us know if you have any feedback or requests for new topics. We'd love to hear from you.

Share this guide