How to Mint an NFT using Metaplex Umi and Candymachine

Joel varghese
5 min readOct 10, 2023

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:

  1. The rpcEndpoint variable is set to the RPC endpoint for the Devnet cluster using the clusterApiUrl function.
  2. candyMachineAddress and treasury are defined as PublicKey objects, representing the Candy Machine address and treasury address based on environment variables.
  3. The umi object is created using the useMemo 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).
  4. The useMemo hook takes an array of dependencies, ensuring that the umi 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]);
  1. The onClick function is defined using the useCallback hook. It handles the logic for minting NFTs from a Candy Machine.
  2. 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.
  3. It fetches the Candy Machine and Candy Guard using the fetchCandyMachine and safeFetchCandyGuard functions, respectively.
  4. It generates a signer (nftMint) for minting NFTs.
  5. It creates a transaction builder and adds instructions to it, including setting the compute unit limit and performing the mintV2 operation.
  6. It sends and confirms the transaction, obtaining the transaction signature and encoding it as a transaction ID (txid).
  7. 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! 🚀🖼️

--

--