spl_token_2022_interface/extension/group_pointer/
instruction.rs1use {
2 crate::{
3 check_program_account,
4 instruction::{encode_instruction, TokenInstruction},
5 },
6 alloc::vec,
7 bytemuck::{Pod, Zeroable},
8 num_enum::{IntoPrimitive, TryFromPrimitive},
9 solana_address::Address,
10 solana_instruction::{AccountMeta, Instruction},
11 solana_nullable::MaybeNull,
12 solana_program_error::ProgramError,
13};
14#[cfg(feature = "serde")]
15use {
16 serde::{Deserialize, Serialize},
17 serde_with::{As, DisplayFromStr},
18};
19
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
23#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
24#[repr(u8)]
25pub enum GroupPointerInstruction {
26 Initialize,
42 Update,
59}
60
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
64#[derive(Clone, Copy, Pod, Zeroable)]
65#[repr(C)]
66pub struct InitializeInstructionData {
67 #[cfg_attr(feature = "serde", serde(with = "As::<Option<DisplayFromStr>>"))]
69 pub authority: MaybeNull<Address>,
70 #[cfg_attr(feature = "serde", serde(with = "As::<Option<DisplayFromStr>>"))]
72 pub group_address: MaybeNull<Address>,
73}
74
75#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
77#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
78#[derive(Clone, Copy, Pod, Zeroable)]
79#[repr(C)]
80pub struct UpdateInstructionData {
81 #[cfg_attr(feature = "serde", serde(with = "As::<Option<DisplayFromStr>>"))]
83 pub group_address: MaybeNull<Address>,
84}
85
86pub fn initialize(
88 token_program_id: &Address,
89 mint: &Address,
90 authority: Option<Address>,
91 group_address: Option<Address>,
92) -> Result<Instruction, ProgramError> {
93 check_program_account(token_program_id)?;
94 let accounts = vec![AccountMeta::new(*mint, false)];
95 Ok(encode_instruction(
96 token_program_id,
97 accounts,
98 TokenInstruction::GroupPointerExtension,
99 GroupPointerInstruction::Initialize,
100 &InitializeInstructionData {
101 authority: authority
102 .try_into()
103 .map_err(|_| ProgramError::InvalidArgument)?,
104 group_address: group_address
105 .try_into()
106 .map_err(|_| ProgramError::InvalidArgument)?,
107 },
108 ))
109}
110
111pub fn update(
113 token_program_id: &Address,
114 mint: &Address,
115 authority: &Address,
116 signers: &[&Address],
117 group_address: Option<Address>,
118) -> Result<Instruction, ProgramError> {
119 check_program_account(token_program_id)?;
120 let mut accounts = vec![
121 AccountMeta::new(*mint, false),
122 AccountMeta::new_readonly(*authority, signers.is_empty()),
123 ];
124 for signer_pubkey in signers.iter() {
125 accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
126 }
127 Ok(encode_instruction(
128 token_program_id,
129 accounts,
130 TokenInstruction::GroupPointerExtension,
131 GroupPointerInstruction::Update,
132 &UpdateInstructionData {
133 group_address: group_address
134 .try_into()
135 .map_err(|_| ProgramError::InvalidArgument)?,
136 },
137 ))
138}