Create Solana NFTs in Minutes

Lokesh JhaLokesh Jha
4 min read

Creating an NFT on the Solana blockchain has become increasingly accessible, thanks to various tools and APIs that simplify the process. In this guide, I'll walk you through creating an NFT for an event using Solana, leveraging Underdog Protocol for handling NFT creation and transfer.

Prerequisites

Before you begin, make sure you have the following:

  1. Node.js installed: Ensure you have Node.js installed on your machine.

  2. Solana Wallet: You need a Solana wallet with sufficient funds to cover transaction fees.

  3. Underdog API Key: Sign up for an API key from Underdog Protocol.

Step 1: Set Up Your Project

First, create a new project directory and initialize it:

mkdir solana-nft-event
cd solana-nft-event
npm init -y

Install the necessary dependencies:

npm install axios @solana/web3.js dotenv

Step 2: Configure Environment Variables

Create a .env file in the root of your project directory and add the following environment variables:

UNDERDOG_API_KEY=your-underdog-api-key
CHAINSTACK_API=https://nd-875-212-309.p2pify.com/9288f69c33dcdf0f8aa0f639985a488d

Replace your-underdog-api-key with your actual Underdog API key.

Step 3: Create the Event and NFT Functions

Create a new file called nftEvent.js and add the following code:

import axios from 'axios';
import solanaweb3 from '@solana/web3.js';

const underdogApiEndpoint = "https://dev.underdogprotocol.com";
const chainStackAPI = process.env.CHAINSTACK_API;
const connection = new solanaweb3.Connection(chainStackAPI);

export interface Event {
    name: string;
    date: string;
    location: string;
    image: string;
    description: string;
    organisationId: string;
}

export interface NFTEvent {
    event: Event;
    symbol: string;
    projectId: string;
    mintAddress: string;
    buyerWalletAddress: string; 
}

export const createEventProject = async (event: Event, symbol: string) => {
    try {
        const config = {
            headers: { Authorization: `Bearer ${process.env.UNDERDOG_API_KEY}` }
        };

        if (!event.name || !event.date || !event.location || !event.organisationId || !symbol) {
            return { message: 'Missing Fields', code: 400 };
        }

        const projectData = {
            "name": event.name,
            "symbol": symbol,
            "image": event.image,
        };

        const createProjectResponse = await axios.post(
            `${underdogApiEndpoint}/v2/projects`,
            projectData,
            config
        );

        const mintAddress = createProjectResponse.data.mintAddress;

        if (mintAddress) {
            let projectAccountInfo = null;
            let retries = 0;

            while (!projectAccountInfo && retries < 50) {
                projectAccountInfo = await connection.getAccountInfo(
                    new solanaweb3.PublicKey(mintAddress)
                );
                await new Promise(resolve => setTimeout(resolve, 100));
                retries++;
            }

            return { message: 'Event created successfully', data: { mintAddress, projectId: createProjectResponse.data.projectId }, code: 200 };
        }

        return { message: 'Error in creating project', data: null, code: 400 };

    } catch (error) {
        console.error('Error creating event in createEventProject:', error);
        return { message: 'Internal Server error: Function createEventProject.', data: null, code: 400 };
    }
};

export const createNftForEvent = async (event: NFTEvent) => {
    try {
        const config = {
            headers: { Authorization: `Bearer ${process.env.UNDERDOG_API_KEY}` }
        };

        const nftData = {
            "name": event.event.name,
            "symbol": event.symbol,
            "image": event.event.image,
        };

        const createNftResponse = await axios.post(
            `${underdogApiEndpoint}/v2/projects/${event.projectId}/nfts`,
            nftData,
            config
        );

        let retrieveNFT = null;
        let retries = 0;

        do {
            retrieveNFT = await axios.get(
                `${underdogApiEndpoint}/v2/projects/${event.projectId}/nfts/${createNftResponse.data.nftId}`,
                config
            );
            await new Promise(resolve => setTimeout(resolve, 100));
            retries++;
        } while ((!retrieveNFT.data || retrieveNFT.data.status !== 'confirmed') && retries < 50);

        const transferResponse = await transferNftToBuyer(
            event.projectId,
            event.buyerWalletAddress,
            createNftResponse.data.nftId
        );

        if (transferResponse.code !== 200) {
            throw new Error("NFT transfer failed");
        }

        return { message: 'NFT created and transferred successfully', data: transferResponse.data, code: 200 };

    } catch (error) {
        console.error('Error creating or transferring NFT in createNftForEvent:', error);
        return { message: 'Internal Server error: Function createNftForEvent.', data: null, code: 400 };
    }
};

export const transferNftToBuyer = async (projectId: string, buyerWalletAddress: string, nftId: string) => {
    try {
        const postBody = {
            receiverAddress: buyerWalletAddress
        };
        const config = {
            headers: { Authorization: `Bearer ${process.env.UNDERDOG_API_KEY}` }
        };

        const createProjectResponse = await axios.post(
            `${underdogApiEndpoint}/v2/projects/${projectId}/nfts/${nftId}/transfer`,
            postBody,
            config
        );

        if (!createProjectResponse.data) {
            throw new Error("NFT transfer failed");
        }

        return { message: 'NFT transferred successfully', data: createProjectResponse.data, code: 200 };
    } catch (error) {
        console.error('Error transferring NFT to buyer:', error);
        return { message: 'Internal Server error: Function transferNftToBuyer.', data: null, code: 400 };
    }
};

Step 4: Use the Functions

You can use these functions to create an event, mint an NFT, and transfer it to the buyer's wallet. Here's an example:

import { createEventProject, createNftForEvent } from './nftEvent.js';

(async () => {
    const event = {
        name: 'Blockchain Conference 2024',
        date: '2024-12-01',
        location: 'New York City',
        image: 'https://example.com/event-image.png',
        description: 'A premier conference on blockchain technology.',
        organisationId: 'org-12345'
    };

    const symbol = 'BLK2024';

    // Create an event project
    const projectResponse = await createEventProject(event, symbol);

    if (projectResponse.code === 200) {
        const { mintAddress, projectId } = projectResponse.data;

        // Create an NFT for the event and transfer it to the buyer
        const nftEvent = {
            event,
            symbol,
            projectId,
            mintAddress,
            buyerWalletAddress: 'buyer-wallet-address'
        };

        const nftResponse = await createNftForEvent(nftEvent);

        console.log(nftResponse.message);
    } else {
        console.error('Failed to create event project:', projectResponse.message);
    }
})();

Conclusion

This guide covers how to create an NFT on the Solana blockchain for an event and transfer it to a buyer's wallet using the Underdog Protocol. By following these steps, you can have your NFTs minted and transferred within minutes.

Feel free to modify the code to fit your specific requirements, such as handling different types of NFTs or integrating with your existing event management system.

0
Subscribe to my newsletter

Read articles from Lokesh Jha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Lokesh Jha
Lokesh Jha

I am a senior software developer and technical writer who loves to learn new things. I recently started writing articles about what I've learned so that others in the community can gain the same knowledge. I primarily work with Node.js, TypeScript, and JavaScript, but I also have past experience with Java and C++. Currently, I'm learning Go and may explore Web3 in the future.