safe_token_2022/extension/default_account_state/
instruction.rs

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