hydra/processors/signing/
sign_metadata.rs

1use 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    /// CHECK: Checked in Program
24    pub holding_account: UncheckedAccount<'info>,
25    #[account(mut)]
26    /// CHECK: Checked in Program
27    pub metadata: UncheckedAccount<'info>,
28    #[account(address=mpl_token_metadata::id())]
29    /// CHECK: Checked in Program
30    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}