spl_token_2022_interface/extension/default_account_state/
instruction.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3use {
4    crate::{
5        check_program_account, error::TokenError, instruction::TokenInstruction,
6        state::AccountState,
7    },
8    num_enum::{IntoPrimitive, TryFromPrimitive},
9    solana_instruction::{AccountMeta, Instruction},
10    solana_program_error::ProgramError,
11    solana_pubkey::Pubkey,
12    std::convert::TryFrom,
13};
14
15/// Default Account State extension instructions
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
18#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
19#[repr(u8)]
20pub enum DefaultAccountStateInstruction {
21    /// Initialize a new mint with the default state for new Accounts.
22    ///
23    /// Fails if the mint has already been initialized, so must be called before
24    /// `InitializeMint`.
25    ///
26    /// The mint must have exactly enough space allocated for the base mint (82
27    /// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
28    /// then space required for this extension, plus any others.
29    ///
30    /// Accounts expected by this instruction:
31    ///
32    ///   0. `[writable]` The mint to initialize.
33    ///
34    /// Data expected by this instruction:
35    ///   `crate::state::AccountState`
36    Initialize,
37    /// Update the default state for new Accounts. Only supported for mints that
38    /// include the `DefaultAccountState` extension.
39    ///
40    /// Accounts expected by this instruction:
41    ///
42    ///   * Single authority
43    ///   0. `[writable]` The mint.
44    ///   1. `[signer]` The mint freeze authority.
45    ///
46    ///   * Multisignature authority
47    ///   0. `[writable]` The mint.
48    ///   1. `[]` The mint's multisignature freeze authority.
49    ///   2. `..2+M` `[signer]` M signer accounts.
50    ///
51    /// Data expected by this instruction:
52    ///   `crate::state::AccountState`
53    Update,
54}
55
56/// Utility function for decoding a `DefaultAccountState` instruction and its
57/// data
58pub fn decode_instruction(
59    input: &[u8],
60) -> Result<(DefaultAccountStateInstruction, AccountState), ProgramError> {
61    if input.len() != 2 {
62        return Err(TokenError::InvalidInstruction.into());
63    }
64    Ok((
65        DefaultAccountStateInstruction::try_from(input[0])
66            .or(Err(TokenError::InvalidInstruction))?,
67        AccountState::try_from(input[1]).or(Err(TokenError::InvalidInstruction))?,
68    ))
69}
70
71fn encode_instruction(
72    token_program_id: &Pubkey,
73    accounts: Vec<AccountMeta>,
74    instruction_type: DefaultAccountStateInstruction,
75    state: &AccountState,
76) -> Instruction {
77    let mut data = TokenInstruction::DefaultAccountStateExtension.pack();
78    data.push(instruction_type.into());
79    data.push((*state).into());
80    Instruction {
81        program_id: *token_program_id,
82        accounts,
83        data,
84    }
85}
86
87/// Create an `Initialize` instruction
88pub fn initialize_default_account_state(
89    token_program_id: &Pubkey,
90    mint: &Pubkey,
91    state: &AccountState,
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        DefaultAccountStateInstruction::Initialize,
99        state,
100    ))
101}
102
103/// Create an `Initialize` instruction
104pub fn update_default_account_state(
105    token_program_id: &Pubkey,
106    mint: &Pubkey,
107    freeze_authority: &Pubkey,
108    signers: &[&Pubkey],
109    state: &AccountState,
110) -> Result<Instruction, ProgramError> {
111    check_program_account(token_program_id)?;
112    let mut accounts = vec![
113        AccountMeta::new(*mint, false),
114        AccountMeta::new_readonly(*freeze_authority, signers.is_empty()),
115    ];
116    for signer_pubkey in signers.iter() {
117        accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
118    }
119    Ok(encode_instruction(
120        token_program_id,
121        accounts,
122        DefaultAccountStateInstruction::Update,
123        state,
124    ))
125}