0

I am aiming to Cross Program Invoke the transfer method of token_metadata_program.

The method takes optional parameters:

...
    #[account(6, optional, name="edition", desc="Edition of token asset")]
    #[account(7, optional, writable, name="owner_token_record", desc="Owner token record account")]
    #[account(8, optional, writable, name="destination_token_record", desc="Destination token record account")]
    #[account(9, signer, name="authority", desc="Transfer authority (token owner or delegate)")]
...

How can I properly forge the CPI call to skip the optional accounts?

What I have so far:

pub fn initialize_auction_2(ctx: Context<InitializeAuction2> ... ) {
    ...

    let transfer_accounts = MetadataTransfer {
            token: ctx.accounts.signer_withdraw_wallet.to_account_info(),
            token_owner: ctx.accounts.signer.to_account_info(),
            destination: ctx.accounts.treasury_token.to_account_info(),
            destination_owner: ctx.accounts.treasury.to_account_info(),
            mint: ctx.accounts.treasury_mint.to_account_info(),
            metadata: ctx.accounts.metadata.to_account_info(),
            edition: ctx.accounts.edition.to_account_info(),
            owner_token_record: ctx.accounts.owner_token_record.to_account_info(),
            destination_token_record: ctx.accounts.destination_token_record.to_account_info(),
            authority: ctx.accounts.signer.to_account_info(),
            payer: ctx.accounts.signer.to_account_info(),
            system_program: ctx.accounts.system_program.to_account_info(),
            sysvar_instructions: ctx.accounts.sysvar_instructions.to_account_info(),
            spl_token_program: ctx.accounts.token_program.to_account_info(),
            spl_ata_program: ctx.accounts.associated_token_program.to_account_info(),
            authorization_rules: ctx.accounts.auth_rules.to_account_info(),
            authorization_rules_program:ctx.accounts.auth_rules_token_program.to_account_info(),
        };

        let cpi_ctx = CpiContext::new_with_signer(
            ctx.accounts.token_metadata_program.to_account_info(),
            transfer_accounts,
            signer_seeds
        );

        token_metadata_transfer(cpi_ctx, 1)?;

Where token_metadata_transfer is defined as:

pub fn token_metadata_transfer<'info>(
    ctx: CpiContext<'_, '_, '_, 'info, MetadataTransfer<'info>>,
    amount: u64,
) -> Result<()> {
    let ix = build_mpl_token_metadata_instruction_with_builder(
        ctx.accounts.authority.key,
        ctx.accounts.authority.key,
        ctx.accounts.token.key,
        ctx.accounts.destination_owner.key,
        Some(*ctx.accounts.destination.key),
        ctx.accounts.metadata.key,
        ctx.accounts.payer.key,
        None,
        ctx.accounts.mint.key,
        None,
        Some(*ctx.accounts.edition.key),
        amount,
    );

    solana_program::program::invoke_signed(
        &ix, 
        &[
            ctx.accounts.token.clone(), // Token account
            ctx.accounts.token_owner.clone(), // Token account Owner
            ctx.accounts.destination.clone(), // Destination token account
            ctx.accounts.destination_owner.clone(), // Destination token account owner
            ctx.accounts.mint.clone(),  // Mint
            ctx.accounts.metadata.clone(), // Token Metadata
            ctx.accounts.edition.clone(), // Edition
            ctx.accounts.owner_token_record.clone(), // Owner token record
            ctx.accounts.destination_token_record.clone(), // Destination token record
            ctx.accounts.authority.clone(), // Authority
            ctx.accounts.payer.clone(), // Payer
            ctx.accounts.system_program.clone(), // System Program
            ctx.accounts.sysvar_instructions.clone(), // Sysvar Instructions
            ctx.accounts.spl_token_program.clone(), // SPL Token Program
            ctx.accounts.spl_ata_program.clone(), // System Program
            ctx.accounts.authorization_rules.clone(), // Authorization rules
            ctx.accounts.authorization_rules_program.clone(), // Authorization rules program
        ], ctx.signer_seeds).map_err(Into::into)

If I try to comment one of the Optional accounts from the accounts list passed to invoke_signed the mpl_token_metadata complains that:

Instruction references an unknown account <pubkey>

What other options do I have?

1 Answer 1

2

The MPL token metadata program exports a builder that you can use to create your CPI instruction.

Check how the Candy Machine uses it: https://github.com/metaplex-foundation/mpl-candy-machine/blob/main/programs/candy-guard/program/src/guards/nft_payment.rs#L149

1
  • Thank you, this is useful. I am drawing inspiration from that at the moment. From the code, it's calling spl_transfer if the token is non programmable. Although the mpl_token_metadata::transfer should take care of that as well if used correctly. Anyhow, appreciate the answer, I am RO as well, hmu on telegram @danielpavel19 Commented Aug 3, 2023 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.