1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use {
crate::{
error::TokenError,
extension::{
set_account_type, AccountType, BaseStateWithExtensions, ExtensionType,
StateWithExtensions,
},
processor::Processor,
state::Account,
},
solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::ProgramResult,
msg,
program::invoke,
pubkey::Pubkey,
system_instruction,
sysvar::{rent::Rent, Sysvar},
},
};
pub fn process_reallocate(
program_id: &Pubkey,
accounts: &[AccountInfo],
new_extension_types: Vec<ExtensionType>,
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let token_account_info = next_account_info(account_info_iter)?;
let payer_info = next_account_info(account_info_iter)?;
let system_program_info = next_account_info(account_info_iter)?;
let authority_info = next_account_info(account_info_iter)?;
let authority_info_data_len = authority_info.data_len();
let mut current_extension_types = {
let token_account = token_account_info.data.borrow();
let account = StateWithExtensions::<Account>::unpack(&token_account)?;
Processor::validate_owner(
program_id,
&account.base.owner,
authority_info,
authority_info_data_len,
account_info_iter.as_slice(),
)?;
account.get_extension_types()?
};
if new_extension_types
.iter()
.any(|extension_type| extension_type.get_account_type() != AccountType::Account)
{
return Err(TokenError::InvalidState.into());
}
current_extension_types.extend_from_slice(&new_extension_types);
let needed_account_len = ExtensionType::get_account_len::<Account>(¤t_extension_types);
if token_account_info.data_len() >= needed_account_len {
return Ok(());
}
msg!(
"account needs realloc, +{:?} bytes",
needed_account_len - token_account_info.data_len()
);
token_account_info.realloc(needed_account_len, false)?;
let rent = Rent::get()?;
let new_minimum_balance = rent.minimum_balance(needed_account_len);
let lamports_diff = new_minimum_balance.saturating_sub(token_account_info.lamports());
invoke(
&system_instruction::transfer(payer_info.key, token_account_info.key, lamports_diff),
&[
payer_info.clone(),
token_account_info.clone(),
system_program_info.clone(),
],
)?;
let mut token_account = token_account_info.data.borrow_mut();
set_account_type::<Account>(&mut token_account)?;
Ok(())
}