Skip to content

Conversation

grod220
Copy link
Member

@grod220 grod220 commented Aug 8, 2025

  • Adds SyncMetadataToToken2022 instruction to sync TokenMetadata from an unwrapped Token-2022 mint (later will be adding spl-token) to its wrapped Token-2022 mint. Initializes if missing, otherwise updates only changed fields and removes stale additional_metadata keys.

  • CreateMint no longer initializes TokenMetadata. This is a follow up from Add metadata extensions on CreateMint #208 (comment).

  • MintCustomizer trait methods simplified further to only what is needed.

@grod220 grod220 force-pushed the sync-metadata-token-2022-pt-1 branch from 9e5e2df to b0d4176 Compare August 8, 2025 10:52
Comment on lines -25 to -38
fn pre_initialize_extensions(
wrapped_mint_account: &AccountInfo,
wrapped_token_program_account: &AccountInfo,
) -> ProgramResult;

/// Customizes extensions for the wrapped mint *after* the base mint is
/// initialized. This is for extensions that require the mint to be
/// initialized, like `TokenMetadata`.
fn post_initialize_extensions<'a>(
wrapped_mint_account: &AccountInfo<'a>,
wrapped_token_program_account: &AccountInfo,
wrapped_mint_authority_account: &AccountInfo<'a>,
mint_authority_signer_seeds: &[&[u8]],
) -> ProgramResult;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplifying this interface and removing the pre-post-mint-init pattern here (given we don't do anything post init in CreateMint anymore)

Comment on lines -92 to -107
invoke_signed(
&initialize_token_metadata(
wrapped_token_program_account.key,
wrapped_mint_account.key,
&wrapped_mint_authority,
wrapped_mint_account.key,
&wrapped_mint_authority,
// Initialized as empty, but separate instructions are available
// to update these fields
"".to_string(),
"".to_string(),
"".to_string(),
),
&cpi_accounts,
&[mint_authority_signer_seeds],
)?;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this saves rent on those wrapped mints without unwrapped mint metadata

Comment on lines +166 to +167
/// Calculate the exact mint account length including all extensions
pub fn calc_mint_len(mint_key: &Pubkey, extensions: &[MintExtension]) -> usize {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this is just for tests, went a bit down the rabbit hole trying to understand exactly how to calculate space for multiple scenarios:

  • no extensions
  • only fixed extensions
  • only variable extensions
  • mixed

Maybe there is some util I am missing, but this was not easy. Eventually this will be used in the cli/client code.

check-cfg = [
'cfg(target_os, values("solana"))',
'cfg(feature, values("frozen-abi", "no-entrypoint"))',
'cfg(feature, values("custom-heap", "custom-panic"))',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New lint warnings require this

@grod220 grod220 changed the title Sync metadata to token-2022 Sync metadata to token-2022 pt. 1 Aug 8, 2025
Copy link

@buffalojoec buffalojoec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this looks great! I left two small comments, but then this can land from my side.

@grod220 grod220 force-pushed the sync-metadata-token-2022-pt-1 branch from b0d4176 to db6a1b9 Compare August 11, 2025 15:59
@grod220 grod220 requested a review from buffalojoec August 11, 2025 16:13
@grod220 grod220 merged commit a94bcb0 into main Aug 11, 2025
10 checks passed
@grod220 grod220 deleted the sync-metadata-token-2022-pt-1 branch August 11, 2025 20:27
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Just a small point

Ok(())
}

type FieldExtractor = Vec<(Field, fn(&TokenMetadata) -> &str)>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this might have changed since I last worked on stuff like this, but function pointers tend to be less performant than closures because the compiler will never inline the code, so typically, Fn is much better than fn

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The challenge is that, for Fn, putting multiple extractors in a vec requires a trait object like Box<dyn Fn(..)> which is not inlineable either. If we really want to inline this though, we can revert the update_fields_if_changed() helper entirely and just do the checks one-after-the-other (prior).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, I forgot about that part, sorry. Never mind then, probably easiest to stick to a function pointer then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants