1

I'm using anchor to write a program that implements the transfer hook interface. One of the extra accounts is an "Authority" owned by the same program with a PDA derived from [b"authority", &seed.key().as_ref()]. The "seed" Pubkey is stored on the "Authority" account itself.

Is it possible to construct a seed from AccountData of an Account that is NOT part of the transfer and is ONLY in the CPI?

The following code results in an AccountNotFound error during the account resolution checks.

#[account]
pub struct Authority {
  pub admin: Pubkey,
  pub seed: Pubkey,
  pub bump: u8,
}

The ExtraAccountMetaList is initialized with:

let metas = vec![
  ExtraAccountMeta::new_with_seeds(
    &[
       Seed::Literal {
         bytes: b"authority".to_vec(),
       },
       Seed::AccountData {
         account_index: 5,   // Index of account in ExecuteTransferHook
         data_index: 8 + 32, // Index of `Authority` seed
         length: 32,         // Length of `Authority` seed
       },
     ],
     false,
     false,
  )?
];

ExtraAccountMetaList::init::<ExecuteInstruction>(&mut data, &metas)?;

Transfer hook accounts and logic is as follows:

#[derive(Accounts)]
pub struct ExecuteTransferHook<'info> {
    #[account(
      token::mint = mint,
      token::authority = owner,
    )]
    pub source_token: InterfaceAccount<'info, TokenAccount>,
    pub mint: InterfaceAccount<'info, Mint>,
    #[account(
      token::mint = mint,
    )]
    pub destination_token: InterfaceAccount<'info, TokenAccount>,
    pub owner: UncheckedAccount<'info>,
    #[account(
      seeds = [META_LIST_ACCOUNT_SEED, mint.key().as_ref()],
      bump
    )]
    pub extra_account_meta_list: UncheckedAccount<'info>,

    #[account(
      seeds = [b"authority", authority.seed.as_ref()],
      bump = authority.bump,
    )]
    pub authority: Account<'info, Authority>,
}

pub fn handler(_ctx: Context<ExecuteTransferHook>) -> Result<()> {
    Ok(())
}

1 Answer 1

1

ExtraAccountMeta seeds can only reference accounts in the array before it. So no self-referencing.

add_to_cpi_instruction is used to construct the CPI from Token2022 to the Transfer Hook program.

Simplified source

for extra_meta in extra_account_metas.data().iter() {
  // Creates the list of accounts that can be used to resolve the current ExtraAccountMeta
  let account_key_data_refs = cpi_account_infos
    .iter()
    .map(|info| {
      let key = *info.key;
      let data = info.try_borrow_data()?;
      Ok((key, data))
    })
    .collect::<Result<Vec<_>, ProgramError>>()?;

  // 
  extra_meta.resolve(
    &cpi_instruction.data,
    &cpi_instruction.program_id,
      |usize| {
         account_key_data_refs
           .get(usize)
           .map(|(pubkey, opt_data)| (pubkey, Some(opt_data.as_ref())))
       },
  )?

  // Adds next ExtraAccountMeta to `cpi_account_infos` to be used in next iteration
  cpi_account_infos.push(account_info);
}

Full source here

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.