How to Mint an NFT using Metaplex Umi and Candymachine
NFTs represent unique digital assets, such as artwork, collectibles, and even virtual real estate, and have taken the digital world by storm. Behind this NFT revolution lies the process of minting, which is essentially creating these unique tokens on the blockchain.
In this tutorial, we’ll take you through the journey of building your very own NFT minting application. Hold strong.
What is Umi and how it will help in our development
Umi is like a toolkit that helps create special computer programs for Solana. Imagine it as a box of tools for building these programs. It has a set of basic tools that other tools can use. What’s great is that you can pick and choose the specific tools you need. Umi even comes with some ready-to-use tools, so developers can start working on their projects right away without having to build everything from scratch. It’s all about giving people the freedom to create what they want with the right tools.
🕸 Set up project
We have made a frontend skeleton, you can clone it on your device, and install the packages.
git clone https://github.com/joelvarghese6/mint-nft-frontend
cd mint-nft-frontend
npm install
you’ll need to install the Umi framework and the Candy Machine JavaScript library.
npm install \
@metaplex-foundation/umi \
@metaplex-foundation/umi-bundle-defaults \
@metaplex-foundation/umi-signer-wallet-adapters \
@solana/web3.js \
@metaplex-foundation/mpl-candy-machine@alpha \
@metaplex-foundation/mpl-token-metadata@alpha \
@metaplex-foundation/mpl-toolbox
✨ Fetch a Candy Machine
We have created a project in the following candy machine account 6DiJS6qSKSWwrPgiqxzKYLqsXTha2Nmwi7kPZzhQvm89, so you don’t have to. If you want to learn how to create an NFT collection with candymachine I have another tutorial you can read.
First, we have to create a .env file and add the values
Make sure you add in your Candy Machine address, and the wallet address you used to create the nft collection:
echo > .env
PUBLIC_CANDY_MACHINE_ID=<CANDYMACHINE_ID> //my dog candymachine ID [6DiJS6qSKSWwrPgiqxzKYLqsXTha2Nmwi7kPZzhQvm89]
PUBLIC_TREASURY=<YOUR_WALLET_ADDRESS> // Wallet address you used to launch the collection
Pop into /components/candymachineNFTs.tsx
You'll see a bunch of setups has already been done for you. We're going to be fetching "pages" of items on the Candy Machine with the getPage
function. Before we can do that, we'll have to fetch the Candy Machine metadata account.
Set up the metaplex
object with a connection right above the empty fetchCandyMachine
function:
const [candyMachineAddress, setCandyMachineAddress] = useState(process.env.PUBLIC_CANDY_MACHINE_ID)
const [candyMachineData, setCandyMachineData]: any = useState(null)
const [pageItems, setPageItems]: any = useState(null)
const [page, setPage] = useState(1)
const metaplex = Metaplex.make(connection)
const fetchCandyMachine = async () => {
setPage(1)
try {
const candyMachine = await metaplex
.candyMachinesV2()
.findByAddress({ address: new PublicKey(candyMachineAddress) })
setCandyMachineData(candyMachine)
} catch (e) {
alert("Please submit a valid CMv2 address.")
}
}
const getPage = async (page: number, perPage: number) => {
const pageItems = candyMachineData.items.slice(
(page - 1) * perPage,
page * perPage
)
// fetch metadata of NFTs for page
let nftData = []
for (let i = 0; i < pageItems.length; i++) {
let fetchResult = await fetch(pageItems[i].uri)
let json = await fetchResult.json()
nftData.push(json)
}
// set state
console.log(nftData)
setPageItems(nftData)
}
//Rest of the code
What we’re doing here in the getPage() function is slicing the items
array into chunks of 10. Then we're fetching the metadata for each NFT in the page and storing it in nftData
. Finally, we're setting the pageItems
state variable to the nftData
we just fetched.
This means at any time our app will only render the NFTs for the current page. Nice!
We have successfully added the candy machine logic, now if you save it you will be able to see the nfts. Just run ‘npm run dev’
Next, we have to implement the minting function.
Open up src/components/connected.tsx
and let's get going. We'll start off with creating the umi instance at the top of the component:
//previous imports
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import { generateSigner, transactionBuilder, publicKey, some } from '@metaplex-foundation/umi';
import { fetchCandyMachine, mintV2, mplCandyMachine, safeFetchCandyGuard } from "@metaplex-foundation/mpl-candy-machine";
import { walletAdapterIdentity } from '@metaplex-foundation/umi-signer-wallet-adapters';
import { mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata';
import { setComputeUnitLimit } from '@metaplex-foundation/mpl-toolbox';
import { clusterApiUrl } from '@solana/web3.js';
const rpcEndpoint = clusterApiUrl('devnet');
const candyMachineAddress = publicKey(process.env.PUBLIC_CANDY_MACHINE_ID);
const treasury = publicKey(process.env.PUBLIC_TREASURY);
const umi = useMemo(() =>
createUmi(rpcEndpoint)
.use(walletAdapterIdentity(wallet))
.use(mplCandyMachine())
.use(mplTokenMetadata()),
[wallet, mplCandyMachine, walletAdapterIdentity, mplTokenMetadata, rpcEndpoint, createUmi]
);
What we have done in the above code is explained below:
- The
rpcEndpoint
variable is set to the RPC endpoint for the Devnet cluster using theclusterApiUrl
function. candyMachineAddress
andtreasury
are defined as PublicKey objects, representing the Candy Machine address and treasury address based on environment variables.- The
umi
object is created using theuseMemo
hook. This object is an instance of UMI (Unified Metaplex Interface) and is configured to use various plugins such as wallet adapter identity, Metaplex Candy Machine (mplCandyMachine), and Metaplex Token Metadata (mplTokenMetadata). - The
useMemo
hook takes an array of dependencies, ensuring that theumi
object is recreated when any of the listed dependencies change. This is a common pattern for optimizing performance in React applications.
const onClick = useCallback(async () => {
if (!wallet.publicKey) {
toast("Wallet not connected")
return;
}
// Fetch the Candy Machine.
const candyMachine = await fetchCandyMachine(
umi,
candyMachineAddress,
);
// Fetch the Candy Guard.
const candyGuard = await safeFetchCandyGuard(
umi,
candyMachine.mintAuthority,
);
try {
// Mint from the Candy Machine.
const nftMint = generateSigner(umi);
const transaction = await transactionBuilder()
.add(setComputeUnitLimit(umi, { units: 800_000 }))
.add(
mintV2(umi, {
candyMachine: candyMachine.publicKey,
candyGuard: candyGuard?.publicKey,
nftMint,
collectionMint: candyMachine.collectionMint,
collectionUpdateAuthority: candyMachine.authority,
mintArgs: {
solPayment: some({ destination: treasury }),
},
})
);
const { signature } = await transaction.sendAndConfirm(umi, {
confirm: { commitment: "confirmed" },
});
const txid = bs58.encode(signature);
toast("Mint Success")
} catch (error: any) {
toast("Something happened")
}
}, [wallet, connection, getUserSOLBalance, umi, candyMachineAddress, treasury]);
- The
onClick
function is defined using theuseCallback
hook. It handles the logic for minting NFTs from a Candy Machine. - It checks whether the wallet is connected. If not, it displays a toast message and returns, indicating that the wallet needs to be connected for the minting process.
- It fetches the Candy Machine and Candy Guard using the
fetchCandyMachine
andsafeFetchCandyGuard
functions, respectively. - It generates a signer (
nftMint
) for minting NFTs. - It creates a transaction builder and adds instructions to it, including setting the compute unit limit and performing the mintV2 operation.
- It sends and confirms the transaction, obtaining the transaction signature and encoding it as a transaction ID (txid).
- If the transaction is successful, it displays a success toast message. Otherwise, it displays an error toast message.
Congratulations! 🎉 You’ve successfully learned how to mint your very first NFT using Umi. I hope this tutorial has been informative and has helped demystify the process of creating and minting NFTs.
Now, it’s time to put your newfound knowledge into action. To see your NFT creation in action, remember to run your application by using the following command: npm run dev
Thank you for taking this journey with us. We wish you the best of luck in your NFT endeavors, and we can’t wait to see the incredible digital art and assets you’ll create in the future. Happy minting! 🚀🖼️