spl_token_2022/extension/scaled_ui_amount/
processor.rs1use {
2 crate::{
3 check_program_account,
4 error::TokenError,
5 extension::{
6 scaled_ui_amount::{
7 instruction::{
8 InitializeInstructionData, ScaledUiAmountMintInstruction,
9 UpdateMultiplierInstructionData,
10 },
11 PodF64, ScaledUiAmountConfig, UnixTimestamp,
12 },
13 BaseStateWithExtensionsMut, PodStateWithExtensionsMut,
14 },
15 instruction::{decode_instruction_data, decode_instruction_type},
16 pod::PodMint,
17 processor::Processor,
18 },
19 solana_program::{
20 account_info::{next_account_info, AccountInfo},
21 clock::Clock,
22 entrypoint::ProgramResult,
23 msg,
24 pubkey::Pubkey,
25 sysvar::Sysvar,
26 },
27 spl_pod::optional_keys::OptionalNonZeroPubkey,
28};
29
30fn try_validate_multiplier(multiplier: &PodF64) -> ProgramResult {
31 let float_multiplier = f64::from(*multiplier);
32 if float_multiplier.is_sign_positive() && float_multiplier.is_normal() {
33 Ok(())
34 } else {
35 Err(TokenError::InvalidScale.into())
36 }
37}
38
39fn process_initialize(
40 _program_id: &Pubkey,
41 accounts: &[AccountInfo],
42 authority: &OptionalNonZeroPubkey,
43 multiplier: &PodF64,
44) -> ProgramResult {
45 let account_info_iter = &mut accounts.iter();
46 let mint_account_info = next_account_info(account_info_iter)?;
47 let mut mint_data = mint_account_info.data.borrow_mut();
48 let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut mint_data)?;
49
50 let extension = mint.init_extension::<ScaledUiAmountConfig>(true)?;
51 extension.authority = *authority;
52 try_validate_multiplier(multiplier)?;
53 extension.multiplier = *multiplier;
54 extension.new_multiplier_effective_timestamp = 0.into();
55 extension.new_multiplier = *multiplier;
56 Ok(())
57}
58
59fn process_update_multiplier(
60 program_id: &Pubkey,
61 accounts: &[AccountInfo],
62 new_multiplier: &PodF64,
63 effective_timestamp: &UnixTimestamp,
64) -> ProgramResult {
65 let account_info_iter = &mut accounts.iter();
66 let mint_account_info = next_account_info(account_info_iter)?;
67 let owner_info = next_account_info(account_info_iter)?;
68 let owner_info_data_len = owner_info.data_len();
69
70 let mut mint_data = mint_account_info.data.borrow_mut();
71 let mut mint = PodStateWithExtensionsMut::<PodMint>::unpack(&mut mint_data)?;
72 let extension = mint.get_extension_mut::<ScaledUiAmountConfig>()?;
73 let authority =
74 Option::<Pubkey>::from(extension.authority).ok_or(TokenError::NoAuthorityExists)?;
75
76 Processor::validate_owner(
77 program_id,
78 &authority,
79 owner_info,
80 owner_info_data_len,
81 account_info_iter.as_slice(),
82 )?;
83
84 try_validate_multiplier(new_multiplier)?;
85 let clock = Clock::get()?;
86 extension.new_multiplier = *new_multiplier;
87 let int_effective_timestamp = i64::from(*effective_timestamp);
88 if int_effective_timestamp < 0 {
90 extension.new_multiplier_effective_timestamp = 0.into();
91 } else {
92 extension.new_multiplier_effective_timestamp = *effective_timestamp;
93 }
94 if clock.unix_timestamp >= int_effective_timestamp {
97 extension.multiplier = *new_multiplier;
98 }
99 Ok(())
100}
101
102pub(crate) fn process_instruction(
103 program_id: &Pubkey,
104 accounts: &[AccountInfo],
105 input: &[u8],
106) -> ProgramResult {
107 check_program_account(program_id)?;
108 match decode_instruction_type(input)? {
109 ScaledUiAmountMintInstruction::Initialize => {
110 msg!("ScaledUiAmountMintInstruction::Initialize");
111 let InitializeInstructionData {
112 authority,
113 multiplier,
114 } = decode_instruction_data(input)?;
115 process_initialize(program_id, accounts, authority, multiplier)
116 }
117 ScaledUiAmountMintInstruction::UpdateMultiplier => {
118 msg!("ScaledUiAmountMintInstruction::UpdateScale");
119 let UpdateMultiplierInstructionData {
120 effective_timestamp,
121 multiplier,
122 } = decode_instruction_data(input)?;
123 process_update_multiplier(program_id, accounts, multiplier, effective_timestamp)
124 }
125 }
126}