hydra/processors/signing/
sign_metadata.rs1use crate::error::HydraError;
2use crate::state::Fanout;
3use crate::utils::validation::assert_owned_by;
4use anchor_lang::prelude::*;
5
6use spl_token::solana_program::program::invoke_signed;
7
8#[derive(Accounts)]
9pub struct SignMetadata<'info> {
10 #[account(mut)]
11 pub authority: Signer<'info>,
12 #[account(
13 seeds = [b"fanout-config", fanout.name.as_bytes()],
14 has_one = authority,
15 bump
16 )]
17 pub fanout: Account<'info, Fanout>,
18 #[account(
19 constraint = fanout.account_key == holding_account.key(),
20 seeds = [b"fanout-native-account", fanout.key().as_ref()],
21 bump
22 )]
23 pub holding_account: UncheckedAccount<'info>,
25 #[account(mut)]
26 pub metadata: UncheckedAccount<'info>,
28 #[account(address=mpl_token_metadata::id())]
29 pub token_metadata_program: UncheckedAccount<'info>,
31}
32
33pub fn sign_metadata(ctx: Context<SignMetadata>) -> Result<()> {
34 let metadata = ctx.accounts.metadata.to_account_info();
35 let holding_account = &ctx.accounts.holding_account;
36 assert_owned_by(&metadata, &mpl_token_metadata::id())?;
37 let meta_data = metadata.try_borrow_data()?;
38 if meta_data[0] != mpl_token_metadata::state::Key::MetadataV1 as u8 {
39 return Err(HydraError::InvalidMetadata.into());
40 }
41 drop(meta_data);
42 let ix = mpl_token_metadata::instruction::sign_metadata(
43 ctx.accounts.token_metadata_program.key(),
44 metadata.key(),
45 holding_account.key(),
46 );
47 invoke_signed(
48 &ix,
49 &[metadata.to_owned(), holding_account.to_account_info()],
50 &[&[
51 "fanout-native-account".as_bytes(),
52 ctx.accounts.fanout.key().as_ref(),
53 &[*ctx.bumps.get("holding_account").unwrap()],
54 ]],
55 ).map_err(|e| {
56 error::Error::ProgramError(ProgramErrorWithOrigin{
57 program_error: e,
58 error_origin: None,
59 compared_values: None
60 })
61 })?;
62 Ok(())
63}