Skip to main content

Programmable NFTs

info

A newer version of this page is available in the Developer Hub. Click here to read it.

Introduction

Version 1.7 of Token Metadata introduced a new type of asset class called Programmable NFTs allowing, amongst other things, creators to enforce royalties on secondary sales.

Since version 1.0 of Candy Machine Core and version 1.0 of Candy Guard, it is now possible to mint Programmable NFTs from candy machines and even update the token standard of existing candy machines.

info

Note that, for JavaScript clients, the Metaplex JS SDK does not and will not support minting Programmable NFTs from candy machines. This is because we released a new Umi-compatible library that does support everything on the programs, which is the new recommended way to manage candy machines in JavaScript.

Alternatively, if you do not wish to switch to the Umi framework, you may instead use the Solita-generated libraries mpl-candy-machine-core from v0.2.1 and mpl-candy-guard from v0.4.1.

For new candy machines

A new instruction called initializeV2 has been added to the Candy Machine Core program. This instruction is similar to the initialize instruction, but it allows you to specify the token standard you want to use for your candy machine. This instruction will mark the newly created Candy Machine as V2 to differentiate it from the V1 Candy Machines that do not store the token standard. These new fields are using existing padding in the Candy Machine account data to avoid breaking changes in the Candy Machine serialization logic.

The initializeV2 instruction can also be used to create a Candy Machine that mints regular NFTs and, therefore, the initialize instruction is now deprecated. Note that no changes are needed for the Candy Guard program here since it delegates to the Candy Machine Core when minting the NFT.

Also, note that some optional accounts may be required depending on the token standard you choose. For example, the ruleSet account may be provided to assign a specific rule set to all minted Programmable NFTs. If no ruleSet account is provided, it will use the rule set of the Collection NFT if any. Otherwise, minted Programmable NFTs will simply not have any rule set assigned. On the other hand, the ruleSet account will be ignored when minting regular NFTs.

Additionally, the collectionDelegateRecord account should now refer to the new Metadata Delegate Record from Token Metadata.

You may want to read the "Create Candy Machines" section of this documentation for more details but here are some examples on how to use our SDKs to create a new Candy Machine that mints Programmable NFTs.

JavaScript — Umi library (recommended)

import { TokenStandard } from "@metaplex-foundation/mpl-token-metadata";
import { create } from "@metaplex-foundation/mpl-candy-machine";
import { generateSigner } from "@metaplex-foundation/umi";

await create(umi, {
// ...
tokenStandard: TokenStandard.ProgrammableNonFungible,
}).sendAndConfirm(umi);

API References: create

JavaScript — SDK

This operation is not supported by the JS SDK but you may use the underlying Solita-generated library instead like so.

import { createInitializeV2Instruction } from "@metaplex-foundation/mpl-candy-machine-core";
import { TokenStandard } from "@metaplex-foundation/mpl-token-metadata";

const initializeV2Instruction: TransactionInstruction =
createInitializeV2Instruction(
{
authorityPda,
collectionUpdateAuthority,
candyMachine,
authority,
payer,
ruleSet,
collectionMetadata,
collectionMint,
collectionMasterEdition,
collectionDelegateRecord,
tokenMetadataProgram,
systemProgram,
sysvarInstructions,
},
{
data: {...},
tokenStandard: TokenStandard.ProgrammableNonFungible,
}
);

API References: Typedoc, Program.

For existing candy machines

It is possible to update the token standard of existing Candy Machines via the new setTokenStandard instruction. When calling this instruction on a Candy Machine V1, it will also upgrade the Candy Machine to V2 and store the token standard in the account data.

You may want to read the "Update Token Standard" section of this documentation for more details but here are some examples on how to use our SDKs to update the token standard of an existing Candy Machine to Programmable NFTs.

JavaScript — Umi library (recommended)

import { TokenStandard } from "@metaplex-foundation/mpl-token-metadata";
import { setTokenStandard } from "@metaplex-foundation/mpl-candy-machine";

await setTokenStandard(umi, {
candyMachine: candyMachine.publicKey,
collectionMint: candyMachine.collectionMint,
collectionUpdateAuthority,
tokenStandard: TokenStandard.ProgrammableNonFungible,
}).sendAndConfirm(umi);

API References: setTokenStandard

JavaScript — SDK

This operation is not supported by the JS SDK but you may use the underlying Solita-generated library instead like so.

import { createSetTokenStandardInstruction } from "@metaplex-foundation/mpl-candy-machine-core";
import { TokenStandard } from "@metaplex-foundation/mpl-token-metadata";

const setTokenStandardInstruction: TransactionInstruction =
createSetTokenStandardInstruction(
{
authority,
authorityPda,
candyMachine,
collectionAuthorityRecord,
collectionDelegateRecord,
collectionMetadata,
collectionMint,
collectionUpdateAuthority,
payer,
ruleSet,
sysvarInstructions,
tokenMetadataProgram,
},
{
tokenStandard: TokenStandard.ProgrammableNonFungible,
}
);

API References: Typedoc, Program.

Additionally, a new setCollectionV2 instruction has been added to support setting a collection that is compatible with Programmable NFTs. This instruction also works with regular NFTs and deprecates the setCollection instruction.

Here as well, you can read more about it in the "Update Collection" section of this documentation.

JavaScript — Umi library (recommended)

import { setCollectionV2 } from "@metaplex-foundation/mpl-candy-machine";

await setCollectionV2(umi, {
candyMachine: candyMachine.publicKey,
collectionMint: candyMachine.collectionMint,
collectionUpdateAuthority: collectionUpdateAuthority.publicKey,
newCollectionMint: newCollectionMint.publicKey,
newCollectionUpdateAuthority,
}).sendAndConfirm(umi);

API References: setCollectionV2

JavaScript — SDK

This operation is not supported by the JS SDK but you may use the underlying Solita-generated library instead like so.

import { createSetCollectionV2Instruction } from "@metaplex-foundation/mpl-candy-machine-core";

const setCollectionV2Instruction: TransactionInstruction =
createSetCollectionV2Instruction({
authority,
authorityPda,
candyMachine,
collectionDelegateRecord,
collectionMetadata,
collectionMint,
collectionUpdateAuthority,
newCollectionDelegateRecord,
newCollectionMasterEdition,
newCollectionMetadata,
newCollectionMint,
newCollectionUpdateAuthority,
payer,
sysvarInstructions,
tokenMetadataProgram,
});

API References: Typedoc, Program.

A new minting instruction

The mint instruction of both the Candy Machine Core and the Candy Guard programs has been updated to support minting Programmable NFTs. This new instruction is called mintV2 and it is similar to the mint instruction, but requires additional accounts to be passed in. Here as well, the new mintV2 instructions can be used to mint regular NFTs and, therefore, they deprecate the existing mint instructions.

The entire "Minting" page has been updated to use the new mintV2 instructions but here's a quick example of how to use them with Programmable NFTs.

JavaScript — Umi library (recommended)

import { mintV2 } from "@metaplex-foundation/mpl-candy-machine";
import { setComputeUnitLimit } from "@metaplex-foundation/mpl-toolbox";
import { transactionBuilder, generateSigner } from "@metaplex-foundation/umi";

const nftMint = generateSigner(umi);
await transactionBuilder()
.add(setComputeUnitLimit(umi, { units: 800_000 }))
.add(
mintV2(umi, {
candyMachine: candyMachine.publicKey,
nftMint,
collectionMint: collectionNft.publicKey,
collectionUpdateAuthority: collectionNft.metadata.updateAuthority,
})
)
.sendAndConfirm(umi);

API References: mintV2

JavaScript — SDK

This operation is not supported by the JS SDK but you may use the underlying Solita-generated library instead like so.

import { createMintV2Instruction } from "@metaplex-foundation/mpl-candy-guard";

const mintV2Instruction: TransactionInstruction = createMintV2Instruction(
{
candyGuard,
candyMachine,
candyMachineAuthorityPda,
candyMachineProgram,
collectionDelegateRecord,
collectionMasterEdition,
collectionMetadata,
collectionMint,
collectionUpdateAuthority,
minter,
nftMasterEdition,
nftMetadata,
nftMint,
nftMintAuthority,
payer,
recentSlothashes,
splTokenProgram,
sysvarInstructions,
token,
tokenMetadataProgram,
tokenRecord,
anchorRemainingAccounts: [], // Any remaining accounts used by registered guards.
},
{
label: null, // Or the label of the group when minting from one.
mintArgs: new Uint8Array([]), // The serialized data to pass to registered guards when applicable.
}
);

API References:

Note that some of the guards offered by the Candy Guard program have also been updated to support Programmable NFTs. Whilst the updates do not introduce breaking changes when minting regular NFTs, they may expect more remaining accounts when minting depending on the token standard.

The guards affected by these changes are:

  • The nftBurn and nftPayment guards now allow the burned/sent NFT to be a Programmable NFT.
  • The FreezeSolPayment and FreezeTokenPayment guards. Since Programmable NFTs are by definition always frozen, they are Locked when minted via a Utility delegate and Unlocked when the thaw conditions have been met.

Additional reading

You may find the following resources about Programmable NFTs and Candy Machines useful: