Core Candy Machine

Minting

So far, we’ve learned how to create and maintain Candy Machines. We’ve seen how to configure them and how to set up complex minting workflows using guard and guard groups. It’s about time we talk about the last piece of the puzzle: Minting!

Basic Minting

As mentioned in the Candy Guards page, there are two programs responsible for minting NFTs from Candy Machines: The Candy Machine Core program — responsible for minting the NFT — and the Candy Guard program which adds a configurable Access Control layer on top of it and can be forked to offer custom guards.

As such, there are two ways to mint from a Candy Machine:

  • From a Candy Guard program which will then delegate the minting to the Candy Machine Core program. Most of the time, you will want to do this as it allows for much more complex minting workflows. You may need to pass extra remaining accounts and instruction data to the mint instruction based on the guards configured in the account. Fortunately, our SDKs make this easy by requiring a few extra parameters and computing the rest for us.

  • Directly from the Core Candy Machine Core program. In this case, only the configured mint authority can mint from it and, therefore, it will need to sign the transaction.

If everything went well, an NFT will be created following the parameters configured in the Core Candy Machine. For instance, if the given Core Candy Machine uses Config Line Settings with Is Sequential set to false, then we will get the next item at random.

Starting from version 1.0 of the Candy Guard program, The mint instruction accepts an additional minter signer which can be different than the existing payer signer. This allows us to create minting workflows where the wallet that mints the NFT is no longer requires to pay SOL fees — such as storage fees and SOL mint payments — as the payer signer will abstract away those fees. Note that the minter signer will still need to pay for token-based fees and will be used to validate the configured guards.

Please note that the latest mint instruction relies on the latest Token Metadata instructions which use a fair amount of compute units. As such, you may need to increase the compute unit limit of the transaction to ensure it is successful. Our SDKs may also help with this.

Mint from a Core Candy Machine

To mint from a Core Candy Machine via a configured Candy Guard account, you may use the mintV1 function and provide the mint address and update authority of the collection NFT the minted NFT will belong to. A minter signer and payer signer may also be provided but they will default to Umi's identity and payer respectively.

As mentioned above, you may need to increase the compute unit limit of the transaction to ensure the mintV1 instruction is successful. You may do this by using the setComputeUnitLimit helper function on the mpl-toolbox Umi library as illustrated in the code snippet below.

import { mintV1 } from '@metaplex-foundation/mpl-core-candy-machine'
import { setComputeUnitLimit } from '@metaplex-foundation/mpl-toolbox'
import { 
  transactionBuilder, 
  generateSigner 
} from '@metaplex-foundation/umi'

const candyMachineId = publicKey('11111111111111111111111111111111')
const coreCollection = publicKey('22222222222222222222222222222222')
const asset = generateSigner(umi)

await transactionBuilder()
  .add(setComputeUnitLimit(umi, { units: 800_000 }))
  .add(
    mintV1(umi, {
      candyMachine: candyMachineId,
      asset,
      collection: coreCollection,
    })
  )
  .sendAndConfirm(umi)

Note that the mintV1 instruction takes care of creating the Mint and Token accounts for us by default and will set the NFT owner to the minter. If you wish to create these yourself beforehand, you may simply give the NFT mind address as a public key instead of a signer. Here's an example using the createMintWithAssociatedToken function from the mpl-toolbox Umi library:

import { mintV1 } from '@metaplex-foundation/mpl-core-candy-machine'
import {
  createMintWithAssociatedToken,
  setComputeUnitLimit,
} from '@metaplex-foundation/mpl-toolbox'
import {
  transactionBuilder,
  generateSigner,
  publicKey,
} from '@metaplex-foundation/umi'

const asset = generateSigner(umi)
const nftOwner = publicKey('11111111111111111111111111111111')

await transactionBuilder()
  .add(setComputeUnitLimit(umi, { units: 800_000 }))
  .add(
    createMintWithAssociatedToken(umi, { mint: nftMint, owner: nftOwner })
    )
  .add(
    mintV1(umi, {
      candyMachine: candyMachineId,
      asset,
      collection: coreCollection,
      owner: nftOwner,
    })
  )
  .sendAndConfirm(umi)

In the rare event that you wish to mint directly from the Core Candy Machine program instead of the Candy Guard Program, you may use the mintAssetFromCandyMachine function instead. This function requires the mint authority of the Core Candy Machine to be provided as a signer and accepts an explicit assetOwner attribute.

import { mintFromCandyMachineV2 } from '@metaplex-foundation/mpl-core-candy-machine'
import { setComputeUnitLimit } from '@metaplex-foundation/mpl-toolbox'
import { transactionBuilder, generateSigner } from '@metaplex-foundation/umi'

const candyMachineId = publicKey('11111111111111111111111111111111')
const coreCollection = publicKey('22222222222222222222222222222222')
const asset = generateSigner(umi)

await transactionBuilder()
  .add(setComputeUnitLimit(umi, { units: 800_000 }))
  .add(
    mintAssetFromCandyMachine(umi, {
      candyMachine: candyMachineId,
      mintAuthority: umi.identity,
      assetOwner: umi.identity.publicKey,
      asset,
      collection: coreCollection,
    })
  )
  .sendAndConfirm(umi)

API References: mintV1, mintAssetFromCandyMachine

Minting With Guards

When minting from a Core Candy Machine that uses a bunch of guards, you may need to provide additional guard-specific information.

If you were to build the mint instruction manually, that information would be provided as a mixture of instruction data and remaining accounts. However, using our SDKs, each guard that requires additional information at mint time defines a set of settings that we call Mint Settings. These Mint Settings will then be parsed into whatever the program needs.

A good example of a guard that requires Mint Settings is the NFT Payment guard which requires the mint address of the NFT we should use to pay for the mint amongst other things.

Each available guard contains its own documentation page and it will tell you whether or not that guard expects Mint Settings to be provided when minting.

If you were to only use guards that do not require Mint Settings, you may mint in the same way described by the “Basic Minting” section above. Otherwise, you’ll need to provide an additional object attribute containing the Mint Settings of all guards that require them. Let’s have a look at what that looks like in practice using our SDKs.

Mint from a Core Candy Machine with guards

When minting via the Umi library, you may use the mintArgs attribute to provide the required Mint Settings.

Here’s an example using the Third Party Signer guard which requires an additional signer and the Mint Limit guard which keeps track of how many times a wallet minted from the Core Candy Machine.

import {
  some,
  generateSigner,
  transactionBuilder,
} from '@metaplex-foundation/umi'
import { create, mintV1 } from '@metaplex-foundation/mpl-core-candy-machine'
import { setComputeUnitLimit } from '@metaplex-foundation/mpl-toolbox'

// Create a Core Candy Machine with guards.
const thirdPartySigner = generateSigner()
await create(umi, {
  // ...
  guards: {
    thirdPartySigner: some({ signer: thirdPartySigner.publicKey }),
    mintLimit: some({ id: 1, limit: 3 }),
  },
}).sendAndConfirm(umi)

// Mint from the Core Candy Machine.
const nftMint = generateSigner(umi)
await transactionBuilder()
  .add(setComputeUnitLimit(umi, { units: 800_000 }))
  .add(
    mintV1(umi, {
      candyMachine: candyMachineId,
      asset,
      collection: coreCollection,
      mintArgs: {
        thirdPartySigner: some({ signer: thirdPartySigner }),
        mintLimit: some({ id: 1 }),
      },
    })
  )
  .sendAndConfirm(umi)

API References: mintV1, DefaultGuardSetMintArgs

Minting With Guard Groups

When minting from a Core Candy Machine using guard groups, we must explicitly select which group we want to mint from by providing its label.

Additionally, Mint Settings may also be required as explained in the previous section. However, the Mint Settings will apply to the “Resolved Guards” of the selected group.

For instance, imagine a Core Candy Machine with the following guards:

  • Default Guards:
    • Bot Tax
    • Third Party Signer
    • Start Date
  • Group 1
    • Label: “nft”
    • Guards:
      • NFT Payment
      • Start Date
  • Group 2
    • Label: “public”
    • Guards:
      • Sol Payment

The Resolved Guards of Group 1 — labelled “nft” — are:

  • Bot Tax: from the Default Guards.
  • Third Party Signer: from the Default Guards.
  • NFT Payment: from Group 1.
  • Start Date: from Group 1 because it overrides the default guard.

Therefore, the provided Mint Settings must be related to these Resolved Guards. In the example above, Mint Settings must be provided for the Third Party Signer guard and the NFT Payment guard.

Mint from a Core Candy Machine with guard groups

When minting from a Core Candy Machine using guard groups, the label of the group we want to select must be provided via the group attribute.

Additionally, the Mint Settings for the Resolved Guards of that group may be provided via the mintArgs attribute.

Here is how we would use the Umi library to mint from the example Core Candy Machine described above.

// Create a Core Candy Machine with guards.
const thirdPartySigner = generateSigner()
await create(umi, {
  // ...
  guards: {
    botTax: some({ lamports: sol(0.001), lastInstruction: true }),
    thirdPartySigner: some({ signer: thirdPartySigner.publicKey }),
    startDate: some({ date: dateTime('2022-10-18T17:00:00Z') }),
  },
  groups: [
    {
      label: 'nft',
      guards: {
        nftPayment: some({ requiredCollection, destination: nftTreasury }),
        startDate: some({ date: dateTime('2022-10-18T16:00:00Z') }),
      },
    },
    {
      label: 'public',
      guards: {
        solPayment: some({ lamports: sol(1), destination: solTreasury }),
      },
    },
  ],
}).sendAndConfirm(umi)

// Mint from the Core Candy Machine.

const candyMachineId = publicKey('11111111111111111111111111111111')
const coreCollection = publicKey('22222222222222222222222222222222')
const asset = generateSigner(umi)

await transactionBuilder()
  .add(setComputeUnitLimit(umi, { units: 800_000 }))
  .add(
    mintV1(umi, {
      candyMachine: candyMachineId,
      asset,
      collection: coreCollection,
      group: some('nft'),
      mintArgs: {
        thirdPartySigner: some({ signer: thirdPartySigner }),
        nftPayment: some({
          mint: nftFromRequiredCollection.publicKey,
          destination: nftTreasury,
          tokenStandard: TokenStandard.NonFungible,
        }),
      },
    })
  )
  .sendAndConfirm(umi)

API References: mintV1, DefaultGuardSetMintArgs

Minting With Pre-Validation

It is important to note that some guards may require additional verification steps before we can mint from their Core Candy Machine. This pre-validation step usually creates an account on the blockchain or rewards the wallet with a token that acts as proof of that verification.

Using the route instruction

One way guards can require a pre-validation step is by using their own special instruction via the “route” instruction.

A good example of that is the Allow List guard. When using this guard, we must verify that our wallet belongs to a predefined list of wallets by calling the route instruction and providing a valid Merkle Proof. If this route instruction is successful, it will create an Allow List PDA for that wallet which the mint instruction can then read to validate the Allow List guard. You can read more about the Allow List guard on its dedicated page.

Using external services

Another way guards may perform that pre-validation step is by relying on an external solution.

For instance, when using the Gatekeeper guard, we must request a Gateway Token by performing a challenge — such as completing a Captcha — which depends on the configured Gatekeeper Network. The Gatekeeper guard will then check for the existence of such Gateway Token to either validate or reject the mint. You can learn more about the Gatekeeper guard on its dedicated page.

Minting With Bot Taxes

One guard you’ll likely want to include in your Core Candy Machine is the Box Tax guard which protects your Core Candy Machine against bots by charging failed mints a configurable amount of SOL. This amount is usually small to hurt bots without affecting genuine mistakes from real users. All bot taxes will be transferred to the Core Candy Machine account so that, once minting is over, you can access these funds by deleting the Core Candy Machine account.

This guard is a bit special and affects the minting behaviour of all other guards. When the Bot Tax is activated and any other guard fails to validate the mint, the transaction will pretend to succeed. This means no errors will be returned by the program but no NFT will be minted either. This is because the transaction must succeed for the funds to be transferred from the bot to the Core Candy Machine account. You can learn more about the Bot Tax guard on its dedicated page.

Conclusion

Congratulations, you now know how Core Candy Machines work from A to Z!

Here are some additional reading resources you might be interested in:

  • All Available Guards: Have a look through all the guards available to you so you can cherry-pick the ones you need.
Previous
Fetching a Candy Machine