How can I access NFT metadata information within an Anchor smart contract?

I’m working on building a custom marketplace contract using Anchor and I need to extract specific metadata from NFTs. I’ve attempted a couple of approaches but haven’t been successful yet.

First, I tried accessing the token account data directly, but that didn’t contain the metadata I needed. Then I attempted to parse the token.to_account_info().data by deserializing it into a metadata structure using mpl_token_metadata::state::Metadata, but this approach resulted in deserialization errors.

What I specifically need to retrieve are:

  • The royaltyPercentage field
  • The creator information from the metadata

Additionally, I’m wondering if it’s possible to modify the primarySaleHappened flag programmatically? This would be useful for my auction system to track initial sales versus secondary market transactions.

use anchor_lang::prelude::*;
use mpl_token_metadata::state::MetadataAccount;

#[derive(Accounts)]
pub struct ProcessNftSale<'info> {
    pub nft_token: Account<'info, TokenAccount>,
    pub metadata_account: AccountInfo<'info>,
    pub buyer: Signer<'info>,
}

pub fn handle_nft_purchase(ctx: Context<ProcessNftSale>) -> Result<()> {
    // Need to access metadata here
    // let metadata_info = ???;
    Ok(())
}

Any guidance on the correct way to read and potentially update NFT metadata would be greatly appreciated.

You’re probably missin the right account constraint. Use Account<'info, MetadataAccount> instead of AccountInfo for the metadata_account. Also check that you’re passin the correct PDA address when callin the instruction - derive it from the mint address using the metaplex seeds.

Hey! Interesting problem. Are you including the metadata program ID in your accounts? When setting up the instruction context, try adding #[account(owner = mpl_token_metadata::ID)] constraint to your metadata account.

Have you tried mpl_token_metadata::utils::try_from_slice_checked instead of direct deserialization? I’ve seen people hit issues with account data padding.

The primarySaleHappened flag is tricky - you need the original creator’s signature to modify it. Is the creator signing your transaction? Without that signature, you’ll get authorization errors.

What deserialization errors are you seeing exactly? That’d help figure out if it’s account constraints or something else. Also, does your marketplace handle compressed NFTs or just standard ones?