Using Compression APIs and ChatGPT, we created and delivered over 300,000 NFTs in just a few hours
Crossmint's Minting API
The Crossmint NFT minting API now supports compressed NFTs on Solana, and last week we put the feature to the test by processing over 300,000 mints. If you’re a Crossmint user, you’re in luck - you were airdropped a piece of history. How did we mint hundreds of thousands of NFTs in a single afternoon? We’ll walk you through it step-by-step.
What are compressed NFTs?
This new technique to mint NFTs drastically reduces the cost to mint an NFT on Solana. It does so by minimizing the usage of on-chain storage in a way that remains secure and decentralized. This approach was developed by Metaplex using their Compressed NFT program, Bubblegum, and Solana Lab’s Concurrent Merkle Tree program, Gummyroll. You can read more about it in Metaplex’s announcement.
The data is accessible by querying indexers that track interactions with compressed NFTs. In our case, we partnered with the team at Helius and utilized their Enhanced Transactions API, as well as the Digital Asset Standard API to query off-chain NFT data. The team was also instrumental in collaborating with us to determine the ideal merkle tree size, and discussing other throughput considerations.
Executing the Airdrop
The Crossmint Mint API makes it very easy to mint an NFT: with one single API call, you get all of the following done for you: (1) handling of cryptocurrency to pay gas fees, (2) secure handling of private keys, (3) interactions with NFT specific smart contracts, (4) data upload to IPFS, (5) generating wallets for recipients - if they don’t have one already.
Thanks to that, the only code we had to write was a script that would iterate through a list of recipients and send each of them an NFT. And it turns out we didn’t have to write any code at all! ChaptGPT, from OpenAI, did this for us:
The following is the documentation for the Crossmint minting API, an API that allows you to mint NFTs directly to your users, in one API call.
Write a nodeJS script that takes a JSON array with N user addresses, and calls the API for each. It should run with ten parallel threads.
*Begin documentation*
--------
Instructions:
// We copy and pasted section 3 from the quickstart here: https://docs.crossmint.com/docs/minting-quickstart#3%EF%B8%8F%E2%83%A3-create-and-send-your-first-nft
And in a few seconds it returned a script like this:
import PQueue from "p-queue";
import userEmails from "./userEmails.json";
const CLIENT_SECRET = ""; // Retrieve from Crossmint console
const PROJECT_ID = ""; // Retrieve from Crossmint console
const CONCURRENT_THREADS = 10;
async function mintNFT(email) {
try {
const response = await fetch(
"http://localhost:3000/api/v1-alpha1/minting/collections/default-solana/nfts",
{
method: "POST",
body: JSON.stringify({
recipient: `email:${email}:solana`,
metadata: {
name: "Compressed Mint Test",
image: "https://www.crossmint.com/assets/crossmint/logo.png",
description:
"Compressed test NFT created using the Crossmint Minting API",
},
}),
headers: {
"x-client-secret": CLIENT_SECRET,
"x-project-id": PROJECT_ID,
"Content-Type": "application/json",
},
}
);
const { id } = await response.json();
return id;
} catch (e) {
console.error(`Error minting NFT for ${email}:`, e);
}
}
async function processEmailAddress(address) {
const nftId = await mintNFT(address);
console.log(`Minting NFT for ${address} with ID: ${nftId}`);
return address;
}
async function main() {
let numMinted = 0;
const queue = new PQueue({ concurrency: CONCURRENT_THREADS });
for (const email of userEmails) {
queue.add(() => processEmailAddress(email));
}
queue.on("completed", async (result) => {
numMinted++;
console.log(
`Completed processing address(totalMinted: ${numMinted}): ${result}`
);
});
queue.on("error", (error) => {
console.error(`Error processing address: ${error}`);
});
await queue.onIdle();
console.log("All addresses processed.");
}
main()
The script reads a list of email addresses from a JSON file named userEmails.json, which contains a list of emails, and uses the p-queue package to process requests concurrently.
The script defines two main functions: mintNFT() and processEmailAddress(). The mintNFT() function makes a fetch request to our mint API endpoint for a given email address, and returns the ID of mint request. You can use this ID in other parts of the Minting API (such as querying for the current status or your request).
We had to modify the script slightly to:
- Ensure we were using the correct project keys
- Update the API route between www.staging.crossmint.com and www.crossmint.com to switch between testing and mainnet
- Create a json file that stored which mints had completed
Finally, we ran the modified script using a virtual machine instance deployed using Digital Ocean’s Droplet feature.The script managed the parallelization of requests and allowed us to complete the airdrop in a few hours and for < 10 cents per NFT, all infra costs included ✨
Compressed NFTs are set to become the new standard for large-scale NFT deployments - unlocking use cases such as NFT receipts, event tickets, video game assets.
If you want to be among the first to create compressed NFTs, head to our docs to get started with the Compression APIs, and mint up to 10,000 NFTs for free!