SoLibrary
  • Solana
  • The Meme Coin Problem and Solution
  • Developing on Solana
  • From Rust To Deployment
  • Solana Blockchain Explorer
  • Building a Solana dAPP
  • Deploying a Solana dApp
  • Deploying a Solana Memecoin using CLI
  • Solana Smart Contracts
  • Send Solana via javascript functions
  • Candy Machine
  • Pump fun APIs
  • Metaplex
  • Metaplex Program Library
  • Solana Program Library
  • UMI Framework
  • Umi and Web3js Differences
  • Fetching Accounts
  • UMI Helpers
  • HTTP Requests
  • Umi's Interfaces
  • Interface implementations
  • Kinobi
  • UMI Plugins
  • Registering Programs
  • Public keys and Signers
  • Connecting RPCS
  • Serializer
  • Storage
  • Transactions
  • Web 3.JS Adapters
  • Metaplex Umi Plugins
  • Core JS SDK v1.0
  • Local Validator
  • SolScriptions
  • FAQ
  • Initialize
  • Write Inscription Data
  • Fetch
  • Clear
  • Close
  • Authority
  • Sharding
  • Getting Started using JavaScript
  • Getting started using the Inscriptions CLI
  • Core Candy Machine
  • Getting Started using JavaScript
  • Candy Guard
  • Assets
  • Creating a Core Candy Machine
  • Inserting Items
  • Updating The Core Candy Machine
  • Guard Groups
  • Special Guard Instructions
  • Fetching a Core Candy Machine
  • Minting
  • Withdrawing a Core Candy Machine
  • Address Gate Guard
  • Allocation
  • Allowlist Guard
  • Asset Burn Guard
  • Asset Burn Multi
  • Asset Payment Guard
  • Asset Payment Multi
  • Asset Mint Limit
  • Bot Tax Guard
  • End Date Guard
  • Edition
  • Freeze Sol Payment guard
  • Freeze Token Payment Guard
  • Gatekeeper Guard
  • Mint Limit Guard
  • NFT Burn Guard
  • NFT Gate Guard
  • NFT Mint Limit Guard
  • NFT Payment Guard
  • Program Gate Guard
  • Redeemed Amount Guard
  • Sol Fixed Fee Guard
  • Sol Payment Guard
  • Start Date Guard
  • Third Party Signer Guard
  • Token Burn Guard
  • Token Gate Guard
  • Token Payment Guard
  • Token2022 Payment Guard
  • Generating Custom Guard Client for Core Candy Machine
Powered by GitBook
On this page
  • The Route Instruction
  • Route Instruction With Groups
  • Conclusion

Special Guard Instructions

As we’ve seen on the previous pages, guards are a powerful way to customize the minting process of your Candy Machines.

PreviousGuard GroupsNextFetching a Core Candy Machine

Last updated 10 months ago

But did you know guards can even provide their own custom instructions?

The Route Instruction

The Core Candy Guard program ships with a special instruction called the “Route” instruction.

This instruction allows us to select a specific guard from our Core Candy Machine and run a custom instruction that is specific to this guard. We call it the “Route” instruction because it will route our request to the selected guard.

This feature makes guards even more powerful as they can ship with their own program logic. It enables guards to:

  • Decouple the verification process from the minting process for heavy operations.

  • Provide custom features that would otherwise require the deployment of a custom program.

To call a route instruction, we must specify which guard we want to route that instruction to as well as provide the route settings it expects. Note that if we try to execute the “route” instruction by selecting a guard that does not support it, the transaction will fail.

Since there can only be one “route” instruction per registered guard on a Candy Guard program, it is common to provide a Path attribute in the route settings to distinguish between multiple features offered by the same guard.

For instance, a guard adding support for Frozen NFTs — that can only be thawed once minting is over — could use their route instruction to initialize the treasury escrow account as well as allow anyone to thaw a minted NFT under the right conditions. We could distinguish these two features by using a Path attribute equal to “init” for the former and “thaw” for the latter.

You will find a detailed explanation of the route instruction of each guard that supports it and their underlying paths .

Let’s take a minute to illustrate how the route instruction works by providing an example. The guard, for instance, supports the route instruction in order to verify that the minting wallet is part of the preconfigured list of wallets.

It does that using which means we need to create a hash of the entire list of allowed wallets and store that hash — known as the Merkle Root — on the guard settings. For a wallet to prove it is on the allowed list, it must provide a list of hashes — known as the Merkle Proof — that allows the program to compute the Merkle Root and ensure it matches the guard’s settings.

Therefore, the Allow List guard uses its route instruction to verify the Merkle Proof of a given wallet and, if successful, creates a small PDA account on the blockchain that acts as verification proof for the mint instruction.

Candy MachineOwner: Candy Machine Core ProgramCandy GuardOwner: Candy Guard ProgramGuardsAllow List...MintCandy Guard ProgramAccess ControlMintCandy Machine Core ProgramMint LogicNFTRouteCandy Machine Core ProgramVerify Merkle ProofAllow List PDA

So why can’t we just verify the Merkle Proof directly within the mint instruction? That’s simply because, for big allow lists, Merkle Proofs can end up being pretty lengthy. After a certain size, it becomes impossible to include it within the mint transaction that already contains a decent amount of instructions. By separating the validation process from the minting process, we make it possible for allow lists to be as big as we need them to be.

Call the route instruction of a guard

JavaScript

You may use the route function to call the route instruction of a guard using the Umi library. You will need to pass the guard’s name via the guard attribute and its route settings via the routeArgs attribute.

Here is an example using the Allow List guard which validates the wallet’s Merkle Proof before minting.

import {
  create,
  route,
  getMerkleProof,
  getMerkleRoot,
} from '@metaplex-foundation/mpl-core-candy-machine'

// Prepare the allow list.
// Let's assume the first wallet on the list is the Metaplex identity.
const allowList = [
  'GjwcWFQYzemBtpUoN5fMAP2FZviTtMRWCmrppGuTthJS',
  '2vjCrmEFiN9CLLhiqy8u1JPh48av8Zpzp3kNkdTtirYG',
  'AT8nPwujHAD14cLojTcB1qdBzA1VXnT6LVGuUd6Y73Cy',
]
const merkleRoot = getMerkleRoot(allowList)

// Create a Candy Machine with an Allow List guard.
await create(umi, {
  // ...
  guards: {
    allowList: some({ merkleRoot }),
  },
}).sendAndConfirm(umi)

// If we try to mint now, it will fail because
// we did not verify our Merkle Proof.

// Verify the Merkle Proof using the route instruction.
await route(umi, {
  candyMachine: candyMachine.publicKey,
  guard: 'allowList',
  routeArgs: {
    path: 'proof',
    merkleRoot,
    merkleProof: getMerkleProof(
      allowList,
      'GjwcWFQYzemBtpUoN5fMAP2FZviTtMRWCmrppGuTthJS'
    ),
  },
}).sendAndConfirm(umi)

// If we try to mint now, it will succeed.

Route Instruction With Groups

When calling the route instruction whilst using guard groups, it is important to specify the group label of the guard we wish to select. This is because we may have multiple guards of the same type across different groups and the program needs to know which one it should use for the route instruction.

For instance, say we had an Allow List of handpicked VIP wallets in one group and another Allow List for the winners of a raffle in another group. Then saying we want to verify the Merkle Proof for the Allow List guard is not enough, we also need to know for which group we should perform that verification.

Filter by group when calling the route instruction

JavaScript

When using groups, the route function of the Umi library accepts an additional group attribute of type Option<string> which must be set to the label of the group we want to select.

import {
  create,
  route,
  getMerkleProof,
  getMerkleRoot,
} from "@metaplex-foundation/mpl-core-candy-machine";
import { base58PublicKey, some } from "@metaplex-foundation/umi";

// Prepare the allow lists.
const allowListA = [...];
const allowListB = [...];

// Create a Candy Machine with two Allow List guards.
await create(umi, {
  // ...
  groups: [
    {
      label: "listA",
      guards: {
        allowList: some({ merkleRoot: getMerkleRoot(allowListA) }),
      },
    },
    {
      label: "listB",
      guards: {
        allowList: some({ merkleRoot: getMerkleRoot(allowListB) }),
      },
    },
  ],
}).sendAndConfirm(umi);

// Verify the Merkle Proof by specifying which group to select.
await route(umi, {
  candyMachine: candyMachine.publicKey,
  guard: 'allowList',
  group: some('listA'), // <- We are veryfing using "allowListA".
  routeArgs: {
    path: 'proof',
    merkleRoot: getMerkleRoot(allowListA),
    merkleProof: getMerkleProof(
      allowListA,
      base58PublicKey(umi.identity),
    ),
  },
}).sendAndConfirm(umi);

Conclusion

API References: ,

API References: ,

The route instruction makes guards even more powerful by allowing them to ship with their own custom program logic. Check out the dedicated pages of to see the full feature set of each guard.

Now that we know everything there is to know about setting up Core Candy Machines and their guards, it’s about time we talk about minting. See you on ! You might want to read about , too.

on their respective pages
Allow List
Merkle Trees
React Flow
route
DefaultGuardSetRouteArgs
route
DefaultGuardSetRouteArgs
all available guards
the next page
fetching it