spl_token_2022/extension/group_pointer/
processor.rs

1use {
2    crate::{
3        check_program_account,
4        error::TokenError,
5        extension::{
6            group_pointer::{
7                instruction::{
8                    GroupPointerInstruction, InitializeInstructionData, UpdateInstructionData,
9                },
10                GroupPointer,
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    group_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    if Option::<Pubkey>::from(*authority).is_none()
39        && Option::<Pubkey>::from(*group_address).is_none()
40    {
41        msg!(
42            "The group pointer extension requires at least an authority or an address for \
43             initialization, neither was provided"
44        );
45        Err(TokenError::InvalidInstruction)?;
46    }
47
48    let extension = mint.init_extension::<GroupPointer>(true)?;
49    extension.authority = *authority;
50    extension.group_address = *group_address;
51    Ok(())
52}
53
54fn process_update(
55    program_id: &Pubkey,
56    accounts: &[AccountInfo],
57    new_group_address: &OptionalNonZeroPubkey,
58) -> ProgramResult {
59    let account_info_iter = &mut accounts.iter();
60    let mint_account_info = next_account_info(account_info_iter)?;
61    let owner_info = next_account_info(account_info_iter)?;
62    let owner_info_data_len = owner_info.data_len();
63
64    let mut mint_data = mint_account_info.data.borrow_mut();
65    let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
66    let extension = mint.get_extension_mut::<GroupPointer>()?;
67    let authority =
68        Option::<Pubkey>::from(extension.authority).ok_or(TokenError::NoAuthorityExists)?;
69
70    Processor::validate_owner(
71        program_id,
72        &authority,
73        owner_info,
74        owner_info_data_len,
75        account_info_iter.as_slice(),
76    )?;
77
78    extension.group_address = *new_group_address;
79    Ok(())
80}
81
82pub(crate) fn process_instruction(
83    program_id: &Pubkey,
84    accounts: &[AccountInfo],
85    input: &[u8],
86) -> ProgramResult {
87    check_program_account(program_id)?;
88    match decode_instruction_type(input)? {
89        GroupPointerInstruction::Initialize => {
90            msg!("GroupPointerInstruction::Initialize");
91            let InitializeInstructionData {
92                authority,
93                group_address,
94            } = decode_instruction_data(input)?;
95            process_initialize(program_id, accounts, authority, group_address)
96        }
97        GroupPointerInstruction::Update => {
98            msg!("GroupPointerInstruction::Update");
99            let UpdateInstructionData { group_address } = decode_instruction_data(input)?;
100            process_update(program_id, accounts, group_address)
101        }
102    }
103}