Candy Guards

Guard Groups

With Guard Groups, you can define multiple sets of guards, each with its own specific requirements. Thiscreate a fully customizable minting process tailored to your project's needs by introducing:

  • Phases: by setting up different time constraints to each group,
  • Parallel Groups: by enabling more than one valid group at a given time.

Create a Candy Guard Group

Guard groups work the same way as Candy Guards, but each group is wrapped in a Label: a unique text identifier that makes the group unique and can't be longer than 6 character.

When minting, users must specify the label of the guard group they want to apply. This is important because multiple groups can be active simultaneously, and, if a user mints near the end of one phase but the transaction processes in the next phase, specifying the label ensures they mint under the intended terms.

with phases

As mentioned earlier, Candy Guard Groups allow creating minting phases by assigning different time constraints to each group.

For example, to reward early birds, you could charge 1 SOL from 4 PM to 5 PM, then increase the price to 2 SOL from 5 PM until the Core Candy Machine is sold out. Here’s how you could configure the guards for this setup:

  • Group 1 - Label: early: Sol Payment (1 SOL), Start Date (4pm), End Date (5pm)
  • Group 2 - Label: late: Sol Payment (2 SOL), Start Date (5pm)

And here's the Code Example for it:

Create a Candy Machine with guard groups

import { create } from '@metaplex-foundation/mpl-core-candy-machine'
import { some, sol, dateTime, generateSigner } from '@metaplex-foundation/umi'

const candyMachine = generateSigner();
const collection = publicKey('11111111111111111111111111111111')

await create(umi, {
  candyMachine,
  collection,
  collectionUpdateAuthority: umi.identity,
  itemsAvailable: 1000,
  authority: umi.identity.publicKey,
  groups: [
    {
      label: 'early',
      guards: {
        solPayment: some({ lamports: sol(1), destination: treasury }),
        startDate: some({ date: dateTime('2022-10-18T16:00:00Z') }),
        endDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
      },
    },
    {
      label: 'late',
      guards: {
        solPayment: some({ lamports: sol(2), destination: treasury }),
        startDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
      },
    },
  ],
}).sendAndConfirm(umi)

with default guards

In the create instruction, you can pass both guards and guard groups. The guards field acts as default guards applied to all groups unless a specific group overrides them by enabling its own version.

Here's a quick Recap:

  • If a guard is enabled on the default guards but not on the group’s guards: group uses the default guard.
  • If a guard is enabled on the default guards and on the group’s guards: group uses group guard.
  • If a guard is neither enabled on the default guards nor the group’s guards: group doesn't uses guard.

Note: even when using default guards, a group must always be provided when minting. That means that is not possible to mint using only the default guards.

Here’s how you could configure the guards to include a Bot Tax for both groups:

  • Default Guard: Bot Tax
  • Group 1 - Label: early: Sol Payment (1 SOL), Start Date (4pm), End Date (5pm)
  • Group 2 - Label: late: Sol Payment (2 SOL), Start Date (5pm)

And here's the Code Example for it:

Create a Candy Machine with default guards and guard groups

import { create } from '@metaplex-foundation/mpl-core-candy-machine'
import { some, sol, dateTime, generateSigner } from '@metaplex-foundation/umi'

const candyMachine = generateSigner();
const collection = publicKey('11111111111111111111111111111111')

await create(umi, {
  candyMachine,
  collection,
  collectionUpdateAuthority: umi.identity,
  itemsAvailable: 1000,
  authority: umi.identity.publicKey,
  guards: {
    botTax: some({ lamports: sol(0.001), lastInstruction: true }),
  },
  groups: [
    {
      label: 'early',
      guards: {
        solPayment: some({ lamports: sol(1), destination: treasury }),
        startDate: some({ date: dateTime('2022-10-18T16:00:00Z') }),
        endDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
      },
    },
    {
      label: 'late',
      guards: {
        solPayment: some({ lamports: sol(2), destination: treasury }),
        startDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
      },
    },
  ],
}).sendAndConfirm(umi)

with Parallel Groups

As mentioned earlier, Candy Guard Groups allows more than one valid group at a given time by allowing the buyer to select which group they would like to mint from.

For example, you could offer a discount to holders of a specific NFT collection while letting others mint at the regular price:

  • Default Guard: Bot Tax, Start Date (4pm)
  • Group 1 - Label: collection: Sol Payment (1 SOL), NFT Gate ("Collection Address")
  • Group 2 - Label: public: Sol Payment (2 SOL)

By selecting the collection group, holders of the specified collection will receive a 50% discount on minting.

Update a Candy Guard Group

Updating Guards Group work similarly to how you would update individual Guards.

Note: Using the updateCandyGuard() will update the entire guards object and groups array overrading all existing data, so be sure to fetch the latest candy guard data beforehand to avoid overwriting any existing settings.

Here's an example of changing the Sol Payment guards from the public group of the Parallel Groups example:

Update a Candy Guard Groups

import { some, sol, dateTime } from '@metaplex-foundation/umi'

const candyGuard = await fetchCandyGuard(umi, candyMachine.mintAuthority)

await updateCandyGuard(umi, {
  candyGuard: candyGuard.publicKey,
  guards: candyGuard.guards,
  groups: [
    {
      label: 'early',
      guards: {
        solPayment: some({ lamports: sol(1), destination: treasury }),
        startDate: some({ date: dateTime('2022-10-18T16:00:00Z') }),
        endDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
        botTax: some({ lamports: sol(0.001), lastInstruction: true }),
      },
    },
    {
      label: 'late',
      guards: {
        solPayment: some({ lamports: sol(3), destination: treasury }),
        startDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
        botTax: some({ lamports: sol(0.001), lastInstruction: true }),
      },
    },
  ],
}).sendAndConfirm(umi)
Previous
Overview