Features
Burning Assets
The owner of an asset can burn it using the Burn instruction of the Token Metadata program. This will close all possible accounts associated with the asset and transfer the various rent-exempt fees previously held in the closed accounts to the owner. This instruction accepts the following attributes:
- Authority: The signer that authorizes the burn. Typically, this is the owner of the asset but note that certain delegated authorities can also burn assets on behalf of the owner as discussed in the "Delegated Authorities" page.
- Token Owner: The public key of the current owner of the asset.
- Token Standard: The standard of the asset being burnt. This instruction works for all Token Standards in order to provide a unified interface for burning assets. That being said, it is worth noting that non-programmable assets can be burnt using the Burn instruction of the SPL Token program directly.
The exact accounts closed by the Burn instruction depend on the Token Standard of the asset being burnt. Here's a table that summarizes the accounts for each Token Standard:
| Token Standard | Mint | Token | Metadata | Edition | Token Record | Edition Marker |
|---|---|---|---|---|---|---|
NonFungible | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
NonFungibleEdition | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ if all prints for it are burnt |
Fungible and FungibleAsset | ❌ | ✅ if all tokens are burnt | ❌ | ❌ | ❌ | ❌ |
ProgrammableNonFungible | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
Note that the Mint account is never closed because the SPL Token program does not allow it.
Here is how you can use our SDKs to burn an asset on Token Metadata.
NFT Burn
1import { publicKey } from '@metaplex-foundation/umi';
2import { burnV1, TokenStandard } from '@metaplex-foundation/mpl-token-metadata';
3
4// Assuming umi is set up with mplTokenMetadata plugin
5// See getting-started for full setup
6
7const mintAddress = publicKey('mintAddress...');
8
9// Burn the NFT (removes all accounts and closes token account)
10await burnV1(umi, {
11 mint: mintAddress,
12 authority: umi.identity,
13 tokenOwner: umi.identity.publicKey,
14 tokenStandard: TokenStandard.NonFungible,
15}).sendAndConfirm(umi);
16
17console.log('NFT burned:', mintAddress);
1import {
2 getBurnV1InstructionAsync,
3 TokenStandard,
4} from '@metaplex-foundation/mpl-token-metadata-kit';
5
6// Assuming rpc, rpcSubscriptions, sendAndConfirm, and authority are set up
7// See getting-started for full setup
8
9const mintAddress = 'mintAddress...'; // The NFT mint address
10
11// Burn the NFT (removes all accounts and closes token account)
12const burnIx = await getBurnV1InstructionAsync({
13 mint: mintAddress,
14 authority,
15 payer: authority,
16 tokenOwner: authority.address,
17 tokenStandard: TokenStandard.NonFungible,
18});
19
20await sendAndConfirm({
21 instructions: [burnIx],
22 payer: authority,
23});
24
25console.log('NFT burned:', mintAddress);
1use mpl_token_metadata::instructions::BurnNftCpiBuilder;
2
3BurnNftCpiBuilder::new(&metadata_program_id)
4 .metadata(&metadata)
5 // if your NFT is part of a collection you will need to pass in the collection metadata address.
6 .collection_metadata(collection_metadata.as_ref())
7 .owner(&owner)
8 .mint(&mint)
9 .token_account(&token)
10 .master_edition_account(&edition)
11 .spl_token_program(&spl_token)
12 .invoke()?;
1use anchor_lang::prelude::*;
2use anchor_spl::token::Mint;
3use mpl_token_metadata::instructions::BurnNftCpiBuilder;
4
5#[derive(Accounts)]
6pub struct NftBurnMpl<'info> {
7 #[account(mut)]
8 owner: Signer<'info>,
9 #[account(mut)]
10 mint: Account<'info, Mint>,
11 #[account(mut)]
12 metadata: AccountInfo<'info>,
13 #[account(mut)]
14 token: AccountInfo<'info>,
15 #[account(mut)]
16 edition: AccountInfo<'info>,
17 collection_metadata: Option<AccountInfo<'info>>,
18 spl_token: AccountInfo<'info>,
19 metadata_program_id: AccountInfo<'info>,
20}
21
22pub fn burn_nft_mpl_instruction<'info>(
23 ctx: Context<'_, '_, '_, 'info, NftBurnMpl<'info>>,
24) -> Result<()> {
25 let owner = ctx.accounts.owner.to_account_info();
26 let metadata = ctx.accounts.metadata.to_account_info();
27 let collection_metadata = ctx.accounts.collection_metadata.as_ref().map(|a| a.to_account_info());
28 let mint = ctx.accounts.mint.to_account_info();
29 let token = ctx.accounts.token.to_account_info();
30 let edition = ctx.accounts.edition.to_account_info();
31 let spl_token = ctx.accounts.spl_token.to_account_info();
32 let metadata_program_id = ctx.accounts.metadata_program_id.to_account_info();
33
34 BurnNftCpiBuilder::new(&metadata_program_id)
35 .metadata(&metadata)
36 // if your NFT is part of a collection you will also need to pass in the collection metadata address.
37 .collection_metadata(collection_metadata.as_ref())
38 .owner(&owner)
39 .mint(&mint)
40 .token_account(&token)
41 .master_edition_account(&edition)
42 .spl_token_program(&spl_token)
43 .invoke()?;
44
45 Ok(())
46}
pNFT Burn
pNFTs may require additional accounts to be passed in for the instruction to work. These may include:
- tokenAccount
- tokenRecord
- authorizationRules
- authorizationRulesProgram
1import { publicKey } from '@metaplex-foundation/umi';
2import { burnV1, TokenStandard } from '@metaplex-foundation/mpl-token-metadata';
3
4// Assuming umi is set up with mplTokenMetadata plugin
5
6const mintAddress = publicKey('mintAddress...');
7
8// Burn the Programmable NFT
9// Note: pNFTs have Token Record accounts that are also cleaned up
10await burnV1(umi, {
11 mint: mintAddress,
12 authority: umi.identity,
13 tokenOwner: umi.identity.publicKey,
14 tokenStandard: TokenStandard.ProgrammableNonFungible,
15}).sendAndConfirm(umi);
16
17console.log('pNFT burned:', mintAddress);
1import {
2 getBurnV1InstructionAsync,
3 TokenStandard,
4} from '@metaplex-foundation/mpl-token-metadata-kit';
5
6// Assuming rpc, rpcSubscriptions, sendAndConfirm, and authority are set up
7
8const mintAddress = 'mintAddress...'; // The pNFT mint address
9
10// Burn the Programmable NFT
11// Note: pNFTs have Token Record accounts that are also cleaned up
12const burnIx = await getBurnV1InstructionAsync({
13 mint: mintAddress,
14 authority,
15 payer: authority,
16 tokenOwner: authority.address,
17 tokenStandard: TokenStandard.ProgrammableNonFungible,
18});
19
20await sendAndConfirm({
21 instructions: [burnIx],
22 payer: authority,
23});
24
25console.log('pNFT burned:', mintAddress);
1use mpl_token_metadata::instructions::BurnNftCpiBuilder;
2
3BurnNftCpiBuilder::new(metadata_program_id.account_info())
4 .metadata(metadata.account_info())
5 .collection_metadata(Some(collection_metadata.account_info()))
6 .owner(owner.account_info())
7 .mint(mint.account_info())
8 .token_account(token.account_info())
9 .master_edition_account(edition.account_info())
10 .spl_token_program(spl_token.account_info())
11 .invoke()?;
1use anchor_lang::prelude::*;
2use anchor_spl::token::Mint;
3use mpl_token_metadata::instructions::BurnV1CpiBuilder;
4
5#[derive(Accounts)]
6pub struct PnftBurnMpl<'info> {
7 #[account(mut)]
8 owner: Signer<'info>,
9 #[account(mut)]
10 mint: Account<'info, Mint>,
11 #[account(mut)]
12 metadata: AccountInfo<'info>,
13 #[account(mut)]
14 token: AccountInfo<'info>,
15 #[account(mut)]
16 master_edition: AccountInfo<'info>,
17 #[account(mut)]
18 token_record: AccountInfo<'info>,
19 collection_metadata: Option<AccountInfo<'info>>,
20 spl_token: AccountInfo<'info>,
21 metadata_program_id: AccountInfo<'info>,
22}
23
24pub fn burn_pnft_mpl_instruction<'info>(
25 ctx: Context<'_, '_, '_, 'info, PnftBurnMpl<'info>>,
26) -> Result<()> {
27let owner = ctx.accounts.owner.to_account_info();
28let metadata = ctx.accounts.metadata.to_account_info();
29let mint = ctx.accounts.mint.to_account_info();
30let token = ctx.accounts.token.to_account_info();
31let master_edition = ctx.accounts.master_edition.to_account_info();
32let collection_metadata = ctx
33 .accounts
34 .collection_metadata
35 .as_ref()
36 .map(|a| a.to_account_info());
37let spl_token = ctx.accounts.spl_token.to_account_info();
38let token_record = ctx.accounts.token_record.to_account_info();
39let metadata_program_id = ctx.accounts.metadata_program_id.to_account_info();
40
41BurnV1CpiBuilder::new(&metadata_program_id)
42 .metadata(&metadata)
43 .collection_metadata(collection_metadata.as_ref())
44 .authority(&owner)
45 .mint(&mint)
46 .token(&token)
47 .spl_token_program(&spl_token)
48 .token_record(Some(&token_record))
49 .master_edition(Some(&master_edition))
50 .invoke()?;
51
52Ok(())
53}
