2

I'm trying to transfer tokens from my program that has a transfer hook. I keep getting 0x7dc8348c Error.

My transfer checked call

// transfer the base token from base bank to the payer base token account based on the amount of base token to be received
    token_2022::transfer_checked(
        CpiContext::new_with_signer(
            token_program.to_account_info(),
            TransferChecked {
                from: base_token_bank.to_account_info(),
                mint: base_token.to_account_info(),
                to: payer_base_token_account.to_account_info(),
                authority: amm.to_account_info(),
            },
            &[&[SEED_AMM, &amm.id.to_be_bytes(), &[amm.bump]]],
        ),
        base_recieved,
        base_token.decimals,
    )?;

This is my context

#[derive(Accounts)]
pub struct Buy<'info> {
  #[account(mut)]
    pub payer: Signer<'info>,
    // we use amm to store the SOL balance
    #[account(mut,
        address = Amm::pda(amm.id).0,
    )]
    pub amm: Account<'info, Amm>,
    #[account(
        mut,
        associated_token::mint = base_token,
        associated_token::authority = payer,
        associated_token::token_program = token_program,
    )]
    pub payer_base_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
    #[account(mut,
        associated_token::mint = amm.base_token,
        associated_token::authority = amm,
        associated_token::token_program = token_program,
    )]
    pub base_token_bank: Box<InterfaceAccount<'info, TokenAccount>>,
    #[account(address = Amm::mint_pda(amm.id).0)]
    pub base_token: Box<InterfaceAccount<'info, Mint>>,
    #[account(
        seeds = [b"extra-account-metas", base_token.key().as_ref()],
        bump
    )]
    /// CHECK extra meta list account
    pub extra_meta_list: AccountInfo<'info>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token2022>,
    pub associated_token_program: Program<'info, AssociatedToken>,
}

I invoke the initializeAmm first (initializes the mint with transfer hook and the extra_accounts_meta

pub struct InitializeAmm<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,
    #[account(init,
      payer = authority,
      space = 8 + mem::size_of::<Amm>(),
      seeds = [SEED_AMM, &amm_id.to_be_bytes()],
      bump)]
    pub amm: Box<Account<'info, Amm>>,
    #[account(
        init,
        payer = authority,
        mint::authority = amm,
        mint::decimals = 9,
        mint::token_program = token_program,
        extensions::transfer_hook::authority = amm,
        extensions::transfer_hook::program_id = crate::ID,
        seeds = [SEED_MINT,&amm_id.to_be_bytes()],
        bump
    )]
    pub base_token: Box<InterfaceAccount<'info, Mint>>,
    #[
        account(
            init,
            payer = authority,
            associated_token::authority = amm,
            associated_token::mint = base_token,
            associated_token::token_program = token_program,
        )
    ]
    pub base_token_bank: Box<InterfaceAccount<'info, TokenAccount>>,
    /// CHECK transfer hook program
    #[account(
        mut,
        seeds = [b"extra-account-metas", base_token.key().as_ref()],
        bump
    )]
    pub extra_meta_list: AccountInfo<'info>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token2022>,
    pub associated_token_program: Program<'info, AssociatedToken>,
}

Example transaction: https://explorer.solana.com/tx/22qAMoehhUbmX3jbcqNahy95KdViegfrWpCxMdWZDME7XjY7iRgybfGtRjzAVQFyS51DZcpaQ7T2mszga5cSderd?cluster=devnet

I can provide more info as needed.

1
  • can you share the full instruction and the test you're using to invoke the instruction?
    – john
    Commented Jun 14 at 15:54

2 Answers 2

3

There might not be Anchor helpers yet to create the proper transfer with all the transfer hook accounts. In the meantime, you can use the onchain helpers that come with token-2022 at https://github.com/solana-labs/solana-program-library/blob/master/token/program-2022/src/onchain.rs, e.g.:

    spl_token_2022::onchain::invoke_transfer_checked(
        token_program_info.key,
        source_account_info.clone(),
        mint_info.clone(),
        destination_account_info.clone(),
        authority_info.clone(),
        remaining_accounts,
        amount,
        decimals,
        &[],
    )?;

There's also some samples in the tests at https://github.com/solana-labs/solana-program-library/blob/a1205a683c37c84b99d3a40ace130fae980387e6/token/program-2022-test/tests/transfer_hook.rs#L85

5
  • Does remaining_accounts need to include extra-account-metas and the program account infos as well? I am lost trying to figure out exactly what needs to be in remaining_accounts. Commented Jul 4 at 1:55
  • The remaining_accounts should have the extra-account-metas somewhere, along with all the other accounts that will be required. Assuming the transaction was properly created, you can just pass the Anchor remaining_accounts directly. The helper will look for the extra-account-metas, figure out the required pubkeys, find them in remaining_accounts, and include them
    – Jon C
    Commented Jul 4 at 15:46
  • I passed each account manually (from my ctx, remaining_accounts is empty). &[ ctx.accounts.from_account.to_account_info().clone(), ctx.accounts.product_mint.to_account_info().clone(), ctx.accounts.to_account.to_account_info().clone(), ctx.accounts.cove.to_account_info().clone() //my program, ctx.accounts.extra_account_meta_list.clone(), ctx.accounts.nft_authority.to_account_info().clone(), //this is only extra account ] Cross-program invocation reentrancy not allowed for this instruction Commented Jul 5 at 17:21
  • "A program may directly call itself recursively, but may not be indirectly called recursively (reentered) by another program. Indirect reentrancy will cause the transaction to immediately fail." I just found this snippet from the docs, so is it not possible to transfer a token from within my anchor program? Commented Jul 5 at 17:39
  • That's correct, you can't call back into the token program from your hook
    – Jon C
    Commented Jul 8 at 19:50
2

When a transfer hook program's execute instruction is invoked, all accounts from the initial transfer instruction are converted to readonly

Although the error you're getting seems to be IncorrectAccount. Did you invoke the instruction using the createTransferCheckedWithTransferHookInstruction helper function?

You can reference these anchor transfer hook program examples.

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.