ChatGPT-generated NFTs with Web3 Functions

Gelato Team

Apr 3, 2023

Over the past few months, we’ve seen incredible glimpses of what OpenAI can do. If you’re a web3 developer, you might be asking yourself: what’s a practical example of combining web3 and OpenAI?

In the web3 ecosystem, there are two primary use cases: DeFi and NFTs. DeFi is all about price movements, derivatives, and trading — an area where OpenAI’s predictive capabilities are still unproven. So instead, let’s focus on NFTs, which use randomness to create traits and attributes that define their uniqueness.

Since OpenAI excels at generating images and creative content, combining NFTs and OpenAI makes perfect sense. The challenge is bridging on-chain NFT minting with off-chain image generation. That’s where Gelato’s Web3 Functions come in — providing seamless communication between on-chain and off-chain environments.

Why Gelato Web3 Functions?

Web3 Functions are a decentralized alternative to centralized cloud platforms like AWS or Google Cloud. They allow developers to extend smart contracts with trust-minimized, scalable infrastructure to run off-chain logic while preserving decentralization.

Web3 Functions can run every minute, check on-chain conditions, fetch data from off-chain APIs, and send transactions back to a contract if criteria are met.

Use Case: ChatGPT-generated NFTs with Gelato Web3 Functions

In this scenario, we want to mint NFTs whose images are generated dynamically with OpenAI. Without Gelato Web3 Functions, this would be nearly impossible. With them, it’s simple:

  • User mints an NFT.

  • A Gelato Web3 Function detects new mints.

  • It calls the OpenAI API to generate an image.

  • The image is uploaded to IPFS.

  • The NFT’s metadata is updated with the new image.

NFT Smart Contract

Here’s a simplified ERC-721 contract where anyone can mint an NFT. A special revealNft function is reserved for Gelato’s proxy to update metadata once OpenAI has generated the image.

function mint(bool _isNight) external whenNotPaused {
    require(!hasMinted[msg.sender], "Already minted!");
    tokenIds.increment();
    uint256 newItemId = tokenIds.current();
    _mint(msg.sender, newItemId);
    _setTokenURI(newItemId, notRevealedUri);
    hasMinted[msg.sender] = true;
    tokenIdByUser[msg.sender] = newItemId;
    nightTimeByToken[newItemId] = _isNight;
    emit MintEvent(newItemId);
}

function revealNft(uint256 tokenId, string memory tokenURI) 
    external onlyGelatoMsgSender 
{
    _setTokenURI(tokenId, tokenURI);
    emit MetadataUpdate(tokenId);
}

_isNight allows users to pick a background theme (day or night). revealNft ensures only Gelato’s executor can update metadata after an image is generated.

Gelato Web3 Functions

A Gelato Web3 Function follows this basic schema:

Web3Function.onRun(async (context: Web3FunctionContext) => {
  const { userArgs, storage, secrets, provider } = context;

  // If conditions aren’t met
  return { canExec: false, message: "no execution due…" };

  // If conditions are met
  return { canExec: true, callData: payload };
});

Gathering inputs

const nftAddress = userArgs.nftAddress;
const nftStorageApiKey = await secrets.get("NFT_STORAGE_API_KEY");
const openAiApiKey = await secrets.get("OPEN_AI_API_KEY");
const lastProcessedId = parseInt((await storage.get("lastProcessedId")) ?? "0");

We collect contract addresses, secrets (IPFS and OpenAI keys), and the last processed tokenId from storage.

Detecting new NFTs

const nft = new Contract(nftAddress as string, NFT_ABI, provider);
const currentTokenId = await nft.tokenIds();

if (currentTokenId.eq(BigNumber.from(lastProcessedId))) {
  return { canExec: false, message: "No New Tokens" };
}

const tokenId = lastProcessedId + 1;

Generating an OpenAI image

function generateNftProperties(isNight: boolean) {
  const timeSelected = isNight ? "at night" : "at sunset";
  const description = 
    `A cute robot eating ice cream in Dubai ${timeSelected}, cyberpunk art, 3D, pastel colors`;

  return {
    description,
    attributes: [
      { trait_type: "Time", value: timeSelected },
      { trait_type: "Place", value: "Eth Dubai" },
      { trait_type: "Eating", value: "Gelato" },
      { trait_type: "Powered", value: "Web3 Functions" },
    ],
  };
}

const response = await openai.createImage({
  prompt: nftProps.description,
  size: "512x512",
});
const imageUrl = response.data.data[0].url;

Uploading to IPFS

const imageBlob = (await axios.get(imageUrl, { responseType: "blob" })).data;
const client = new NFTStorage({ token: nftStorageApiKey });
const imageFile = new File([imageBlob], `gelato_bot_${tokenId}.png`, { type: "image/png" });

const metadata = await client.store({
  name: `Eth Dubai GelatoBot #${tokenId}`,
  description: nftProps.description,
  image: imageFile,
  attributes: nftProps.attributes,
  collection: { name: "EthDubai-GelatoBots", family: "ethdubai-gelatobots" },
});

await storage.set("lastProcessedId", tokenId.toString());

Updating on-chain metadata

return {
  canExec: true,
  callData: nft.interface.encodeFunctionData("revealNft", [tokenId, metadata.url]),
};

👉 You can view the full code here.

About Gelato

Gelato is a Web3 Cloud Platform empowering developers to create automated, gasless, and off-chain-aware smart contracts and Layer 2 chains. Over 400 projects use Gelato to power millions of DeFi, NFT, and gaming transactions.

  • Gelato RaaS: Launch your own ZK or OP L2 chain with Gelato middleware built in.

  • Web3 Functions: Connect smart contracts to off-chain data with decentralized cloud functions.

  • Automate: Schedule transactions and automate execution.

  • Relay: Provide gasless transactions via Gelato’s reliable API.

  • Account Abstraction SDK: Built with Safe to combine Gelato’s infra with the most secure contract wallet.

👉 Stay updated: follow Gelato on Twitter.
👉 Want to help build the future of the internet? Explore careers at Gelato.

Ready to build?

Start with a testnet, launch your mainnet in days, and scale with industry-leading UX.

Ready to build?

Start with a testnet, launch your mainnet in days, and scale with industry-leading UX.

Ready to build?

Start with a testnet, launch your mainnet in days, and scale with industry-leading UX.

Ready to build?

Start with a testnet, launch your mainnet in days, and scale with industry-leading UX.