How to implement a function for minting edition NFTs from master edition tokens

I’m working on a Solana project using Rust and the Anchor framework to build NFT functionality. I need to create a method that can mint edition NFTs based on an existing master edition token.

I’m trying to utilize the mpl_token_metadata::instruction::mint_new_edition_from_master_edition_via_token function, but I’m uncertain about two specific parameters. It requires both master_metadata and master_metadata_mint arguments, but the official documentation seems to only require the master record metadata account.

My question is: What specific account keys should I input for the master_metadata and master_metadata_mint parameters?

Here’s my current implementation:

pub fn mint_edition_from_master(
    ctx: Context<MintEditionContext>,
    edition_number: u64,
) -> Result<()> {
    let account_infos = vec![
        ctx.accounts.spl_token.to_account_info(),
        ctx.accounts.edition_metadata.to_account_info(),
        ctx.accounts.edition_account.to_account_info(),
        ctx.accounts.master_edition_account.to_account_info(),
        ctx.accounts.edition_mint.to_account_info(),
        ctx.accounts.mint_authority.to_account_info(),
        ctx.accounts.funding_account.to_account_info(),
        ctx.accounts.holder.to_account_info(),
        ctx.accounts.holder_token_account.to_account_info(),
        ctx.accounts.metadata_authority.to_account_info(),
        ctx.accounts.master_metadata.to_account_info(),
        ctx.accounts.master_metadata.to_account_info(),
        ctx.accounts.system_program.to_account_info(),
        ctx.accounts.rent_sysvar.to_account_info(),
    ];
    
    invoke(&mint_new_edition_from_master_edition_via_token(
        ctx.accounts.spl_token.key(),
        ctx.accounts.edition_metadata.key(),
        ctx.accounts.edition_account.key(),
        ctx.accounts.master_edition_account.key(),
        ctx.accounts.edition_mint.key(),
        ctx.accounts.mint_authority.key(),
        ctx.accounts.funding_account.key(),
        ctx.accounts.holder.key(),
        ctx.accounts.holder_token_account.key(),
        ctx.accounts.metadata_authority.key(),
        ctx.accounts.master_metadata.key(),
        ctx.accounts.master_metadata.key(),
        edition_number
    ), account_infos.as_slice())?;
    
    msg!("Successfully minted edition NFT!");
    Ok(())
}

#[derive(Accounts)]
pub struct MintEditionContext<'info> {
    #[account(mut)]
    pub edition_metadata: UncheckedAccount<'info>,
    #[account(mut)]
    pub edition_account: UncheckedAccount<'info>,
    #[account(mut)]
    pub master_edition_account: UncheckedAccount<'info>,
    #[account(mut)]
    pub edition_mint: UncheckedAccount<'info>,
    #[account(mut)]
    pub edition_mark_account: UncheckedAccount<'info>,
    #[account(mut)]
    pub mint_authority: Signer<'info>,
    #[account(mut)]
    pub funding_account: AccountInfo<'info>,
    #[account(mut)]
    pub holder: UncheckedAccount<'info>,
    #[account(mut)]
    pub holder_token_account: UncheckedAccount<'info>,
    #[account(mut)]
    pub metadata_authority: UncheckedAccount<'info>,
    #[account(mut)]
    pub master_metadata: UncheckedAccount<'info>,
    pub spl_token: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub rent_sysvar: AccountInfo<'info>,
}

Any guidance on the appropriate account mapping would be really beneficial!

Hit this same problem last month while building edition minting. You’re mixing up two different accounts that both relate to the master edition.

master_metadata wants the PDA for the master edition’s metadata account - you’ve got that part right. But master_metadata_mint needs the actual mint account that created the master edition NFT, not the metadata.

Add a master_mint field to your MintEditionContext struct and use that for the second parameter instead of passing master_metadata twice. You should have stored this master mint when you first created the master edition, or you can pass it as a parameter.

One gotcha that tripped me up: make sure your master mint has exactly one token in circulation and is owned by the Token program. The ownership and supply constraints matter here.

Your code’s duplicating master_metadata for both parameters. master_metadata should be the metadata account of your master NFT, but master_metadata_mint needs to be the actual mint account of the master edition token - they’re different accounts. Also missing the master mint field in your struct.

oh interesting! i’ve been working on something similar and hit the same confusion with those parameters. CreativePainter45 is right about the duplication issue, but i’m curious about something…

Looking at your struct, you’re missing the actual master mint account CreativePainter mentioned, but you do have master_metadata defined. So master_metadata should point to your master edition’s metadata PDA (which you have), but for master_metadata_mint you need another field in your struct for the master edition’s mint account.

btw, have you tested this with the metaplex test suite? wondering if there are other gotchas with edition numbering or token account setup that might bite you later.

quick question - are you handling the edition mark account logic separately, or expecting this function to manage it automatically? i see you have edition_mark_account in your struct but it’s not being passed to the instruction call.

what’s your experience with anchor integration been like? any other weird parameter mappings you’ve hit with the mpl functions?