spl_token_2022/extension/group_member_pointer/
processor.rs

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