Since the infrastructure for doing so is so new, building an NFT on Solana can be challenging. Here, I’ll describe how to use The Blockchain API, an API that makes performing many tasks on Solana that you might want to do easier. Think about submitting a feature request on our GitHub repository if you have one.
In this tutorial, we will use Python, but we won’t use any special Python libraries, so you can use any language.
How to Create NFT Collection on Solana
Make sure to create a Pinata account first. For testing, you can use a free account, but for a mainnet NFT launch, you might want to think about the Professional Plan with a Dedicated IPFS Gateway.
Once you’ve signed up for an account, you just need to make sure you have the following installed (each is linked to the installed instructions of you need to install them):
- Node.js version 16.13.0 or newer is recommended
- Git version 2.32.0 or newer
- Yarn version 1.22.17 or newer
- Ts-node version 10.4.0 or newer
For what it’s worth, we will largely adhere to Metaplex’s instructions with a few modifications that let us upload files to IPFS using Pinata.
Read More: What is Solana Faucet
Preparing the Assets
You won’t learn how to create assets for your NFT project in this tutorial. Before the contract can be deployed to Solana, that is a separate endeavor that needs to be completed. So, assuming you have the art created, we’ll walk through how to prep this for upload to IPFS through Metaplex.
The first step is to make a folder for your NFT project assets. From the command line, that will look like this:
mkdir nft-project
Inside that folder, create another folder called assets
. In the assets folder, you will add all of your images. Your images must all have base 0 index labels. That means the first image would be 0.png
and the second would be 1.png
and so on.
Once your images are in the folder, you will need to create the metadata for these images. With Solana NFT metadata, you’ll be at home if you have any prior experience with Ethereum NFT metadata. The architecture is almost identical. Let’s take a look at a basic JSON metadata file structure for NFTs on Solana:
{
"name": "Number #0001",
"symbol": "NB",
"description": "on the blockchain, a grouping of ten numbers. This represents one tenth of a number.",
"image": "0.png",
"attributes": [
{"trait_type": "Layer-1", "value": "0"},
{"trait_type": "Layer-2", "value": "0"},
{"trait_type": "Layer-3", "value": "0"},
{"trait_type": "Layer-4", "value": "1"}
],
"properties": {
"creators": [{"address": "N4f6zftYsuu4yT7icsjLwh4i6pB1zvvKbseHj2NmSQw", "share": 100}],
"files": [{"uri": "0.png", "type": "image/png"}]
},
"collection": {"name": "numbers", "family": "numbers"}
}
The Solana metadata standard is similar to the Ethereum metadata standard in that it has a name, image, and description. As with ETH, attributes, a symbol, and collection information are additional options. The token symbol is typically assigned at contract deployment rather than in the metadata in Ethereum projects. Another difference is the properties
a portion of the You can include a variety of files for your NFTs by using the Solana metadata, which is necessary. You have to have at least one file in that array that points to the same asset as the image
property, but you can include other files that make up your entire NFT: Although this is a really intriguing idea that deserves more investigation, for the purposes of this post, we will only be using NFTs with a single asset.
Here is a link where you can learn more about the Solana NFT metadata standard.
Ok, so we know we have images in the folder. We are aware that those images require specific names. Furthermore, we are aware that JSON metadata files are required. How are we now going to get those JSON files created and added to the assets
folder? You could do this manually, but with a 10,000 NFT project, that would be nearly impossible.
Let’s create the metadata files by writing a script.
From your command line, make sure you are in the nft-project
folder. We will create a new file called metadata-generator.js
by running this command: touch metadata-generator.js
.
Open the new file in your code editor. Although it’s blank, we’ll fill it in right away. We need to loop through all of the images in our assets
folder and create a unique Each must have its own JSON file, which must be given a name and saved in the same assets directory. To do this, we will make use of Node.js fs
which is built into Node.js.
In your metadata-generator.js
file add this code:
const fs = require('fs');const imageDir = fs.readdirSync("./assets");imageDir.forEach(img => {
const metadata = {
name: `Image ${img.split(".")[0]}`,
description: "An image in the NFT collection",
image: img,
properties: {
files: [{ uri: img, "type": "image/png" }],
category: "image",
creators: [{
address: "YOUR_SOL_WALLET_ADDRESS",
share: 100
}]
}
} fs.writeFileSync(`./assets/${img.split(".")[0]`, JSON.stringify(metadata))
});
It goes without saying that you would modify this for your project. Give each of your images a unique name, include the attributes array, etc. This is a very basic example, but it’ll get you going.
To run your script and generate the metadata, you should run this command from the root of your project folder: node metadata-generator.js
.
When the script is finished, you’ll have a assets
folder that has images and JSON files together. It should look like this:
Okay, we are prepared with our resources. It’s time to start using Metaplex right away to get Solana going.
Using Metaplex
A tool called Metaplex makes it much simpler to start an NFT project on Solana. Rather than having to write your smart contract like you would have to do with Ethereum, Metaplex has pre-written contracts that projects can plug into. In order for this to function, Metaplex must be able to access the files related to the NFTs, upload those files, and link them to each token that will be issued.
Although Metaplex has basic support for IPFS, we must use a branch that is open and awaiting merge by the Metaplex team in order to use it with Pinata. I’ll update this post once the pull request has been merged.
Although we’ll be changing the Github branch/repo used for the Metaplex CLI, we’ll still be following the standard Metaplex Candy Machine guide that can be found here.
Clone the branch being used for the pull request that adds Pinata support as the first step. Run the following command in your terminal:
git clone -b add-pinata-support https://github.com/polluterofminds/metaplex ~/metaplex
So that we won’t have to keep track of where the project was cloned, we are copying the directory into the home directory. Inside the new metaplex
repo is code to support the JavaScript CLI we will be making use of. Therefore, we must install the necessary dependencies for that CLI code.
yarn install --cwd ~/metaplex/js/
Checking that the installation was successful next. Remember, we installed ts-node
? We’re going to use that now to run a command for the metaplex cli
.
ts-node ~/metaplex/js/packages/cli/src/candy-machine-v2-cli.ts --version
If everything was installed correctly, a version should print out. We must now verify that the Solana CLI is operational. Run this command to get the version number:
solana --version
If that works, you’re good to go. Make sure the Solana CLI Toolkit is installed if it isn’t already. The CLI will then be used to create the devnet wallet. We can experiment in the Solana devnet without worrying about having a significant financial impact.
Run this command to create your new devnet wallet and store the keys:
solana-keygen new --outfile ~/.config/solana/devnet.json
Now, we can set the default keypair for our Solana CLI interactions:
solana config set --keypair ~/.config/solana/devnet.json
Finally, let’s let the CLI know that we intend to interact with the devnet:
solana config set --url https://api.devnet.solana.com
To confirm this all worked as expected, we can fetch the configuration for Solana like this:
solana config get
The configuration details should print out as a result. If so, you’re ready to get airdropped some SOL!
Despite the fact that this is obviously devnet SOL, communication with the devnet is still required. Run this command:
solana airdrop 2
When that is complete, you can run this command to verify your devnet wallet has the SOL:
solana balance
Check to see if your devnet wallet contains two SOL.
After completing the initial installation and configuration of Solana and Metaplex, we will proceed to setting up the NFT drop.
Drop Configuration
You should read this article in its entirety because this is the most crucial aspect of the entire drop. For NFT drops like this, Metaplex employs a program called Candy Machine, so it’s crucial to ensure your project is set up correctly. The first place where we will notice the effects of using the code from the pull request that enables Pinata support is in this configuration.
You can see that Pinata is not listed as a storage provider in the documents. However, Pinata is an option with the pull request version of Metaplex that you cloned in the beginning!
At the root of your project, create a JSON file called config.json
. Then, enter a configuration like this:
{"price": 0.05,"number": 100,"gatekeeper": null,"solTreasuryAccount": "YOUR DEVNET WALLET ADDRESS","splTokenAccount": null,"splToken": null,"goLiveDate": "01 Jan 2022 00:00:00 GMT","endSettings": null,"whitelistMintSettings": null,"hiddenSettings": null,"storage": "pinata","ipfsInfuraProjectId": null,"ipfsInfuraSecret": null,"pinataJwt": "YOUR PINATA JWT TOKEN","pinataGateway": "YOUR PINATA GATEWAY URL","awsS3Bucket": null,"noRetainAuthority": false,"noMutable": false}
Despite feeling like a lot, this is only the bare minimum configuration needed. You can certainly add a lot more. We’re keeping it straightforward, so don’t worry. There are only five things in this file that need to be changed. Notice the storage
property already points to pinata
. The only version of Metaplex that will support this is the one you cloned from a pull request.
In order to use a Pinata Dedicated Gateway, you must first decide whether to do so. Doing so will give you and anyone who loads your NFTs the best possible performance. It’s not necessary, despite being advised. If you do decide to get a Dedicated Gateway, you’ll need to upgrade to the Professional Plan in Pinata.
To access the Pinata API, you must next obtain a JWT. To do this, select API Keys from the top-right dropdown menu, then click Generate a New API Key. You can either specify which endpoints the key should have access to (pinFileToIPFS) or you can create an admin key that has full access. However, the key needs to have access to pinFileToIPFS. This depends on your security preferences. Here is more information on scoped API keys.
When you’ve created your key a modal will display your API Key, API Secret, and your JWT. We only need the JWT, so copy that and paste it into the pinataJwt
configuration file property’s value.
If you created a Dedicated Gateway, you can paste in your Dedicated Gateway’s URL in the pinataGateway
section of the config file. If you did not upgrade and do not have a Dedicated Gateway, you should update that property to look like this:
pinataGateway: null
Finally, you just need to set the number of items in your NFT collection for the number
property and the price in SOL for the price
property.
There is a ton more you can do, but I want to draw attention to something that many projects probably want to do: conceal the NFT assets until after a reveal date. This is possible with Metaplex and Candy Machine with hidden settings. You can read about that here. We won’t be doing that in this tutorial. This tutorial’s NFT project will show a mint with an immediate reveal.
The final thing you’ll want to change in the config file is the solTreasuryAccount
. This could point to any Solana wallet address, though it should ideally point to your devnet wallet address. To get your devnet wallet address, you can run this in the command line:
solana address
We’re about to upload some files and make our NFT contract!
Uploading to Pinata and Solana
We’ve finished all the prep work. It’s time to upload, which is fortunately easy to do.
In the root of the project directory, run this command in the command line:
ts-node ~/metaplex/js/packages/cli/src/candy-machine-v2-cli.ts upload \
-e devnet \
-k ~/.config/solana/devnet.json \
-cp config.json \
-c nft-project \
./assets
This command will take your config file parse it so that Metaplex knows how to upload your files and how to get the NFT mint info onto Solana. You’ll see in your command line each upload of your asset
folder’s metadata and your asset
folders images. This procedure could take a very long time depending on how many files you are uploading. So crack your favourite cold beverage and sit back and relax.
When the process is done, you’ll need to do one more thing. You’ll need to verify the upload. This enables you to determine whether everything is prepared and whether your NFTs can be produced. You just need to run this command:
ts-node ~/metaplex/js/packages/cli/src/candy-machine-v2-cli.ts verify_upload \
-e devnet \
-k ~/.config/solana/devnet.json \
-c nft-project
If all goes well, you should see a message that includes Ready to deploy!
. Your project is now complete as a result.
If you want to confirm things, you can find the .cache
folder in your nft-project
directory. Open that up, and you’ll see a JSON file with information about your upload. The program.candyMachine
the property will have an Here is the Solana devnet explorer ID, which you can view. Just be sure to set Devnet as your network.
You can now mint your NFT drop. But what do we do now? You probably want to create a website to allow for minting. Fortunately, the Metaplex code base has us covered.
Creating a Minting App
In case you forgot, we copied Metaplex’s pull request version. We cloned that into our home directory. So, from your command line, let’s change to our home directory and into the metaplex project, directly into the sample React app:
cd ~/metaplex/js/packages/fair-launch
You’ll need to install the dependencies like this:
yarn install
Then, launch your code editor and open the project. You’ll see a .env
file in that folder. You should update it to look like this:
REACT_APP_CANDY_MACHINE_ID=YOUR CANDY MACHINE IDREACT_APP_SOLANA_NETWORK=devnetREACT_APP_SOLANA_RPC_HOST=https://api.devnet.solana.comREACT_APP_FAIR_LAUNCH_ID=
Recall how we looked up our project on the Solana Explorer using the Candy Machine ID? We are going to paste that same ID where it says YOUR CANDY MACHINE ID
.
Now, you can run the app with:
yarn start
When the app load, you should see:
A Solana wallet of your choice will be available for connection. Regardless of the wallet you select, make sure it contains some devnet SOL. Remember when we airdropped ourselves some devnet SOL? We can also do that with another address. Make sure you are on devnet, connect your wallet, and then copy the wallet address. From the command line run:
solana airdrop 2 YOUR_ADDRESS
You should now have SOL in your browser-based wallet and be able to mint one of your new NFTs after this is finished. To do so, just click the Mint button:
The transaction must be verified by you. When you do this, the minting procedure should be completed in a matter of seconds. Once finished, your new NFT ought to appear in the collection of NFTs in your wallet.
The image you see of your NFT is being loaded from Pinata. The NFT is loading through either a private IPFS gateway or a dedicated gateway URL, depending on whether you specified one in your configuration file. Observation: If you specified a dedicated gateway URL in the configuration, your NFT asset will not only load more quickly, but it will also be cached so that all subsequent loads are instant. This is illustrated using Phantom Wallet in the example that follows. A public IPFS gateway is being used by the two NFTs that are having loading issues. The two that load almost immediately do so via a Dedicated Gateway.
When viewing your NFTs on Solana NFT marketplaces, the assets will load through the IPFS gateway as well. People can then experience the content exactly how it was intended to be experienced.
Wrapping Up
There is ample evidence of the advantages of storing NFT assets using IPFS. Fast retrieval is a feature of IPFS, as is content addressability, and IPFS is portable (especially when using a Pinata Dedicated Gateway). NFT ownership is transferable in both the media sense and the token sense.
However, integrating IPFS with Solana NFT projects hasn’t always been simple. Hopefully, this guide will change that. Hopefully, it will inspire more imaginative projects.
Happy drop days and happy pinning!