Reputation: 99
[image link to my code]
https://i.sstatic.net/UWtpj.png
I am currently writing a Solana Metaplex NFT program in Rust/Anchor-Solana, specifically working on writing a logic to create a edition NFT from a master edition NFT.
While invoking mpl_token_metadata::instruction::mint_new_edition_from_master_edition_via_token
instruction, I found out that it requires both metadata
and metadata_mint
field as arguments. Whereas, on the metaplex documentation, it seems the instruction only requires the Master record metadata account.
Question:
Which account key, or value, should I put in to each of those fields(metadata
and metadata_mint
) and why?
Code:
pub fn create_new_edition_nft(
ctx: Context<CreateNewEdition>,
edition: u64,
) -> Result<()> {
let edition_infos = vec![
ctx.accounts.token_program.to_account_info(),
ctx.accounts.new_metadata.to_account_info(),
ctx.accounts.new_edition.to_account_info(),
ctx.accounts.master_edition.to_account_info(),
ctx.accounts.new_mint.to_account_info(),
ctx.accounts.new_mint_authority.to_account_info(),
ctx.accounts.payer.to_account_info(),
ctx.accounts.token_account_owner.to_account_info(),
ctx.accounts.token_account.to_account_info(),
ctx.accounts.new_metadata_update_authority.to_account_info(),
ctx.accounts.metadata.to_account_info(),
ctx.accounts.system_program.to_account_info(),
ctx.accounts.rent.to_account_info(),
];
msg!("Edition Account Infos Assigned");
invoke(&mint_new_edition_from_master_edition_via_token(
ctx.accounts.token_program.key(),ctx.accounts.new_metadata.key(),ctx.accounts.new_edition.key(), ctx.accounts.master_edition.key(), ctx.accounts.new_mint.key(),ctx.accounts.new_mint_authority.key(), ctx.accounts.payer.key(), ctx.accounts.token_account_owner.key(), ctx.accounts.token_account.key(), ctx.accounts.new_metadata_update_authority.key(), ctx.accounts.metadata.key(), ctx.accounts.metadata.key(), edition
), edition_infos.as_slice())?;
msg!("A New Edition Nft Minted !!!");
Ok(())
}
#[derive(Accounts)]
pub struct CreateNewEdition<'info> {
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub new_metadata: UncheckedAccount<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub new_edition: UncheckedAccount<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub master_edition: UncheckedAccount<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub new_mint: UncheckedAccount<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub edition_mark_pda: UncheckedAccount<'info>,
#[account(mut)]
pub new_mint_authority: Signer<'info>,
#[account(mut)]
pub payer: AccountInfo<'info>,
// /// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub token_account_owner: UncheckedAccount<'info>,
// /// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub token_account: UncheckedAccount<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub new_metadata_update_authority: UncheckedAccount<'info>,
/// CHECK: This is not dangerous because we don't read or write from this account
#[account(mut)]
pub metadata: UncheckedAccount<'info>,
// #[account(mut)]
pub token_program: Program<'info, Token>,
pub system_program: Program<'info, System>,
/// CHECK: This is not dangerous because we don't read or write from this account
pub rent: AccountInfo<'info>,
}
Documentation Reference:
Documentation for printing a new edition from a master edition:
Upvotes: 1
Views: 513
Reputation: 2114
The documentation on metaplex you are talking about is the documentation of the solana instructions but not the rust api. They are different. If you take a look at the rust code, you will see the differences.
The accounts described in the documentation match the accounts provided by the code:
let accounts = vec![
AccountMeta::new(new_metadata, false),
AccountMeta::new(new_edition, false),
AccountMeta::new(master_edition, false),
AccountMeta::new(new_mint, false),
AccountMeta::new(edition_mark_pda, false),
AccountMeta::new_readonly(new_mint_authority, true),
AccountMeta::new(payer, true),
AccountMeta::new_readonly(token_account_owner, true),
AccountMeta::new_readonly(token_account, false),
AccountMeta::new_readonly(new_metadata_update_authority, false),
AccountMeta::new_readonly(metadata, false),
AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
AccountMeta::new_readonly(sysvar::rent::id(), false),
];
The variable metadata_mint
you are talking about is used to calculate the address of the edition_mark_pda
address on chain:
let (edition_mark_pda, _) = Pubkey::find_program_address(
&[
PREFIX.as_bytes(),
program_id.as_ref(),
metadata_mint.as_ref(),
EDITION.as_bytes(),
as_string.as_bytes(),
],
&program_id,
);
When you compare this with the documentation, you will see what should be provided:
Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number]) where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE).
metadata
:= Master record metadata account
metadata_mint
:= master metadata mint id
Upvotes: 0