Minting Solana NFTs: A Beginner's Guide
Welcome to this guide on minting NFTs on Solana! In our previous write-up, NFTs on Solana: Minting 101, we explored minting using Solana’s command-line tool.
For a real NFT project, minting on demand from a decentralized application (dApp) is essential. This guide will walk you through the process using JavaScript (JS) or TypeScript (TS). If you prefer to dive straight into the solution, check out the Next.js Wonka Example App.
Ecosystem & Tools
Before jumping into the solution, let’s review some key tools, standards, and libraries within the Solana ecosystem:
Solana Web3.js Interface
The web3.js
equivalent for Solana is the @solana/web3.js
library. This library allows you to interact with the Solana blockchain, similar to using Solana’s CLI but through JS. While you can mint an NFT with this library, you’ll need to handle the storage of NFT metadata and the logic for royalties manually. This approach requires more work and is less user-friendly.
Metaplex Ecosystem
Metaplex is a strategic initiative by Solana to build an ecosystem around NFTs. It consists of:
Four programs: These act like contracts for Solana, governing minting and auctioning.
Various projects: These include a storefront builder, an airdrop tool, and more.
You can mint directly through Metaplex’s JS APIs or CLI tools, though it requires understanding the architecture.
Metaplex Candy Machine
Candy Machine is a minting workflow manager built on top of Metaplex. It handles the missing parts from the core Metaplex architecture, such as uploading assets to Arweave and creating metadata accounts. It’s complex but provides significant value for simple NFT projects.
Wonka JS
Wonka JS is a simplified JS layer built on top of Candy Machine, reducing the amount of wiring needed for minting and processing metadata. It makes minting through APIs as simple as possible.
1. Create a Candy Machine
For a simple minting flow, we’ll use Candy Machine + Wonka JS. Here are the high-level steps:
Prepare Assets: Get your PNG assets and their associated JSON metadata ready.
Create Candy Machine: Use the Candy Machine CLI to upload the PNGs to Arweave and create metadata accounts pointing to the correct URI.
Store Candy Machine ID: Save the Candy Machine ID in an
.env
file inside your web app for use with Wonka.
Follow the steps in the Candy Machine: Getting Started documentation to get your Candy Machine ID.
2. Set Up a Web App
With your Candy Machine ready, set up your web app:
Kick Off a Next.js Web App: Run the following command in your terminal to create a new Next.js app:
npx create-next-app my-nft-app cd my-nft-app
You can also use React, but Next.js is recommended for its built-in API Routes, which help with simple backend requests.
Store Environment Variables: Create a
.env
file in the root of your project and add your Candy Machine ID and Solana setup:env NEXT_PUBLIC_CANDY_MACHINE_ID=your_candy_machine_id
Authenticate the User: Ensure the user has a Solana wallet installed. If
window.solana
is available, you can useProvider
from Project Serum, a widely used wallet wrapper in Metaplex. For better management of various Solana wallets, use@solana/wallet-adapter-react
. Here’s an example setup:jsx import { WalletProvider } from '@solana/wallet-adapter-react'; import { ConnectionProvider } from '@solana/wallet-adapter-react'; import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'; import { PhantomWalletAdapter } from '@solana/wallet-adapter-wallets'; const wallets = [new PhantomWalletAdapter()]; const network = WalletAdapterNetwork.Devnet; function MyApp({ Component, pageProps }) { return ( <ConnectionProvider endpoint={network}> <WalletProvider wallets={wallets}> <Component {...pageProps} /> </WalletProvider> </ConnectionProvider> ); } export default MyApp;
3. Mint with Wonka
To mint an NFT, use the mintCandyMachineToken(..)
function from Wonka JS. Here’s an example:
Install Wonka JS:
bashnpm install @wonka/solana
Mint Function:
jsx import { mintCandyMachineToken } from '@wonka/solana'; async function mintNFT(provider) { const candyMachineId = process.env.NEXT_PUBLIC_CANDY_MACHINE_ID; try { const mintTxId = await mintCandyMachineToken(provider, candyMachineId); console.log('Minted NFT with transaction ID:', mintTxId); } catch (error) { console.error('Error minting NFT:', error); } }
Button to Mint:
jsx import { useWallet } from '@solana/wallet-adapter-react'; function MintButton() { const { publicKey, signTransaction } = useWallet(); return ( <button onClick={() => mintNFT({ publicKey, signTransaction })}> Mint NFT </button> ); } export default MintButton;
You can see a working example in the Wonka Next.js Example App.
Conclusion
By following these steps, you can mint NFTs on Solana using a combination of Candy Machine and Wonka JS. This approach simplifies the process and leverages the robust Solana and Metaplex ecosystems. Happy minting!
This guide is designed for beginners and aims to provide a straightforward path to minting NFTs on Solana. For further reading and advanced topics, explore the official documentation of the tools and libraries mentioned.
Creating an NFT on Solana: A Step-by-Step Guide for Beginners
In this guide, we will walk you through the process of creating an NFT (Non-Fungible Token) on the Solana blockchain. An NFT is a cryptographically unique token that cannot be replicated. Unlike ERC20 tokens, which can have many identical tokens, an NFT is one-of-a-kind. We'll create two accounts with wallets: one to mint the NFT and another to receive it. We'll then write code to handle the minting and transferring of the NFT on Solana. If you encounter any issues, refer to the complete solution code at the end of the guide. Let's get started with minting!
Prerequisites
Before you begin, ensure you have the following:
Node.js installed
Familiarity with Terminal/CLI
A text editor
TypeScript installed
What is Solana?
Solana aims to scale blockchain technology for global adoption. Solana Labs, the developers of the Solana Protocol, focus on improving blockchain performance through various methods, including the consensus mechanism.
While Bitcoin uses Proof of Work (PoW) and Ethereum is moving to Proof of Stake (PoS), Solana employs a consensus mechanism called Proof of History (PoH). PoH timestamps each transaction, allowing the network to verify transactions quickly. Solana combines eight core technologies to position itself as a fast, scalable, and secure blockchain.
Setting up the Project Locally
To set up your project, follow these steps:
Open your Terminal and navigate to the folder where you want to create your project.
Run the following commands:
bash mkdir SolanaNFT npm install --prefix ./SolanaNFT @solana/web3.js @solana/spl-token cd SolanaNFT touch index.ts tsc --init --resolveJsonModule true
The first command creates a new project directory called
SolanaNFT
.The second command installs the Solana JavaScript API (
@solana/web3.js
) and the TypeScript library (@solana/spl-token
).The third command creates a new TypeScript file,
index.ts
.The fourth command initializes a TypeScript project and creates a
tsconfig.json
file with the--resolveJsonModule
option enabled.
Connecting to Solana
Open the SolanaNFT
project directory in your text editor. Start by importing the necessary functionality from @solana/web3.js
and @solana/spl-token
:
typescript import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import { createMint, getOrCreateAssociatedTokenAccount, mintTo, setAuthority, transfer } from "@solana/spl-token";
Connect to a Solana Cluster with QuickNode
To build on Solana, you'll need an API endpoint to connect to the network. You can use public nodes or manage your own infrastructure, but for faster response times, we recommend QuickNode. Sign up for a free account and use a Solana Devnet endpoint.
typescript const quicknodeEndpoint = 'https://example.solana-devnet.quiknode.pro/0123456/';
const connection = new Connection(quicknodeEndpoint, "confirmed");
(async () => {
// Remaining code goes here 👇
})();
This code establishes a connection to the Solana Devnet using your QuickNode endpoint. Solana has three networks: mainnet, testnet, and devnet. Devnet is a low-risk environment where you can airdrop SOL tokens to yourself.
Creating a New Wallet and Airdropping SOL
First, create a wallet and fund it. Use the following code to generate a new wallet and airdrop 1 SOL to it:
typescript const fromWallet = Keypair.generate();
const airdropSignature = await connection.requestAirdrop(fromWallet.publicKey, LAMPORTS_PER_SOL);
await connection.confirmTransaction(airdropSignature);
Creating a New Token Mint
Next, create a new token mint and retrieve your token account:
typescript const mint = await createMint(
connection,
fromWallet, // Payer of the transaction
fromWallet.publicKey, // Account that will control the minting
null, // Account that will control the freezing of the token
0 // Location of the decimal place
);
const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
mint,
fromWallet.publicKey
);
Creating an Account to Receive the NFT
Now, create a new wallet and token account to receive the NFT:
typescript const toWallet = Keypair.generate();
const toTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
mint,
toWallet.publicKey
);
Minting the NFT and Sending It
Finally, mint an NFT and send it to the recipient:
typescript let signature = await mintTo(
connection,
fromWallet, // Payer of the transaction fees
mint, // Mint for the account
fromTokenAccount.address, // Address of the account to mint to
fromWallet.publicKey, // Minting authority
1 // Amount to mint
);
await setAuthority(
connection,
fromWallet, // Payer of the transaction fees
mint, // Account
fromWallet.publicKey, // Current authority
0, // Authority type: "0" represents Mint Tokens
null // Setting the new Authority to null
);
signature = await transfer(
connection,
fromWallet, // Payer of the transaction fees
fromTokenAccount.address, // Source account
toTokenAccount.address, // Destination account
fromWallet.publicKey, // Owner of the source account
1 // Number of tokens to transfer
);
console.log("SIGNATURE", signature);
Running the Program
To execute the program, run the following commands:
bash tsc index.ts
node index.js
These commands compile the TypeScript file to JavaScript and then run the JavaScript file. You should see a transaction signature logged in the terminal.
Conclusion
Congratulations! You've successfully created an NFT on the Solana blockchain. The next step is to link this unique token to an asset. Explore further guides to deepen your knowledge of Solana NFTs.
Here is the complete code for reference:
typescript import { Connection, Keypair } from "@solana/web3.js";
import { createMint, getOrCreateAssociatedTokenAccount, mintTo, setAuthority, transfer } from "@solana/spl-token";
const quicknodeEndpoint = 'https://example.solana-devnet.quiknode.pro/0123456/';
const connection = new Connection(quicknodeEndpoint, "confirmed");
const secret = [0...0]; // Replace with your secret key
const fromWallet = Keypair.fromSecretKey(new Uint8Array(secret));
(async () => {
// Create a new token
const mint = await createMint(
connection,
fromWallet, // Payer of the transaction
fromWallet.publicKey, // Account that will control the minting
null, // Account that will control the freezing of the token
0 // Location of the decimal place
);
// Get the token account of the fromWallet Solana address. If it does not exist, create it.
const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
mint,
fromWallet.publicKey
);
// Generate a new wallet to receive the newly minted token
const toWallet = Keypair.generate();
// Get the token account of the toWallet Solana address. If it does not exist, create it.
const toTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
fromWallet,
mint,
toWallet.publicKey
);
// Minting 1 new token to the "fromTokenAccount" account we just returned/created.
let signature = await mintTo(
connection,
fromWallet, // Payer of the transaction fees
mint, // Mint for the account
fromTokenAccount.address, // Address of the account to mint to
fromWallet.publicKey, // Minting authority
1 // Amount to mint
);
await setAuthority(
connection,
fromWallet, // Payer of the transaction fees
mint, // Account
fromWallet.publicKey, // Current authority
0, // Authority type: "0" represents Mint Tokens
null // Setting the new Authority to null
);
signature = await transfer(
connection,
fromWallet, // Payer of the transaction fees
fromTokenAccount.address, // Source account
toTokenAccount.address, // Destination account
fromWallet.publicKey, // Owner of the source account
1 // Number of tokens to transfer
);
console.log("SIGNATURE", signature);
})();
Explore more Solana NFT guides to further enhance your skills and understanding of this technology. Happy minting!
Last updated