spl_token_2022/extension/metadata_pointer/
processor.rs

1use {
2    crate::{
3        check_program_account,
4        error::TokenError,
5        extension::{
6            metadata_pointer::{
7                instruction::{
8                    InitializeInstructionData, MetadataPointerInstruction, UpdateInstructionData,
9                },
10                MetadataPointer,
11            },
12            BaseStateWithExtensionsMut, PodStateWithExtensionsMut,
13        },
14        instruction::{decode_instruction_data, decode_instruction_type},
15        pod::PodMint,
16        processor::Processor,
17    },
18    solana_program::{
19        account_info::{next_account_info, AccountInfo},
20        entrypoint::ProgramResult,
21        msg,
22        pubkey::Pubkey,
23    },
24    spl_pod::optional_keys::OptionalNonZeroPubkey,
25};
26
27fn process_initialize(
28    _program_id: &Pubkey,
29    accounts: &[AccountInfo],
30    authority: &OptionalNonZeroPubkey,
31    metadata_address: &OptionalNonZeroPubkey,
32) -> ProgramResult {
33    let account_info_iter = &mut accounts.iter();
34    let mint_account_info = next_account_info(account_info_iter)?;
35    let mut mint_data = mint_account_info.data.borrow_mut();
36    let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
37
38    let extension = mint.init_extension::<MetadataPointer>(true)?;
39    extension.authority = *authority;
40
41    if Option::<Pubkey>::from(*authority).is_none()
42        && Option::<Pubkey>::from(*metadata_address).is_none()
43    {
44        msg!("The metadata pointer extension requires at least an authority or an address for initialization, neither was provided");
45        Err(TokenError::InvalidInstruction)?;
46    }
47    extension.metadata_address = *metadata_address;
48    Ok(())
49}
50
51fn process_update(
52    program_id: &Pubkey,
53    accounts: &[AccountInfo],
54    new_metadata_address: &OptionalNonZeroPubkey,
55) -> ProgramResult {
56    let account_info_iter = &mut accounts.iter();
57    let mint_account_info = next_account_info(account_info_iter)?;
58    let owner_info = next_account_info(account_info_iter)?;
59    let owner_info_data_len = owner_info.data_len();
60
61    let mut mint_data = mint_account_info.data.borrow_mut();
62    let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
63    let extension = mint.get_extension_mut::<MetadataPointer>()?;
64    let authority =
65        Option::<Pubkey>::from(extension.authority).ok_or(TokenError::NoAuthorityExists)?;
66
67    Processor::validate_owner(
68        program_id,
69        &authority,
70        owner_info,
71        owner_info_data_len,
72        account_info_iter.as_slice(),
73    )?;
74
75    extension.metadata_address = *new_metadata_address;
76    Ok(())
77}
78
79pub(crate) fn process_instruction(
80    program_id: &Pubkey,
81    accounts: &[AccountInfo],
82    input: &[u8],
83) -> ProgramResult {
84    check_program_account(program_id)?;
85    match decode_instruction_type(input)? {
86        MetadataPointerInstruction::Initialize => {
87            msg!("MetadataPointerInstruction::Initialize");
88            let InitializeInstructionData {
89                authority,
90                metadata_address,
91            } = decode_instruction_data(input)?;
92            process_initialize(program_id, accounts, authority, metadata_address)
93        }
94        MetadataPointerInstruction::Update => {
95            msg!("MetadataPointerInstruction::Update");
96            let UpdateInstructionData { metadata_address } = decode_instruction_data(input)?;
97            process_update(program_id, accounts, metadata_address)
98        }
99    }
100}