-
Notifications
You must be signed in to change notification settings - Fork 93
Expand file tree
/
Copy pathset_authority.rs
More file actions
132 lines (115 loc) · 5.03 KB
/
set_authority.rs
File metadata and controls
132 lines (115 loc) · 5.03 KB
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use {
super::validate_owner,
pinocchio::{
account_info::AccountInfo, hint::likely, program_error::ProgramError, pubkey::Pubkey,
ProgramResult,
},
pinocchio_token_interface::{
error::TokenError,
instruction::AuthorityType,
state::{account::Account, load_mut, mint::Mint, Transmutable},
},
};
#[inline(always)]
pub fn process_set_authority(accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult {
// Validates the instruction data.
let (authority_type, new_authority) = if instruction_data.len() >= 2 {
// SAFETY: The expected size of the instruction data is either 2 or 34 bytes:
// - authority_type (1 byte)
// - option + new_authority (1 byte + 32 bytes)
unsafe {
let authority_type = AuthorityType::try_from(*instruction_data.get_unchecked(0))?;
let new_authority = if *instruction_data.get_unchecked(1) == 0 {
None
} else if likely(*instruction_data.get_unchecked(1) == 1)
&& instruction_data.len() >= 34
{
Some(&*(instruction_data.as_ptr().add(2) as *const Pubkey))
} else {
return Err(TokenError::InvalidInstruction.into());
};
(authority_type, new_authority)
}
} else {
return Err(TokenError::InvalidInstruction.into());
};
// Validates the accounts.
let [account_info, authority_info, remaining @ ..] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
if account_info.data_len() == Account::LEN {
// SAFETY: single mutable borrow to `account_info` account data and
// `load_mut` validates that the account is initialized.
let account = unsafe { load_mut::<Account>(account_info.borrow_mut_data_unchecked())? };
if account.is_frozen()? {
return Err(TokenError::AccountFrozen.into());
}
match authority_type {
AuthorityType::AccountOwner => {
// SAFETY: `authority_info` is not currently borrowed.
unsafe { validate_owner(&account.owner, authority_info, remaining)? };
if let Some(authority) = new_authority {
account.owner = *authority;
} else {
return Err(TokenError::InvalidInstruction.into());
}
account.clear_delegate();
account.set_delegated_amount(0);
if account.is_native() {
account.clear_close_authority();
}
}
AuthorityType::CloseAccount => {
let authority = account.close_authority().unwrap_or(&account.owner);
// SAFETY: `authority_info` is not currently borrowed.
unsafe { validate_owner(authority, authority_info, remaining)? };
if let Some(authority) = new_authority {
account.set_close_authority(authority);
} else {
account.clear_close_authority();
}
}
_ => {
return Err(TokenError::AuthorityTypeNotSupported.into());
}
}
} else if account_info.data_len() == Mint::LEN {
// SAFETY: single mutable borrow to `account_info` account data and
// `load_mut` validates that the mint is initialized.
let mint = unsafe { load_mut::<Mint>(account_info.borrow_mut_data_unchecked())? };
match authority_type {
AuthorityType::MintTokens => {
// Once a mint's supply is fixed, it cannot be undone by setting a new
// mint_authority.
let mint_authority = mint.mint_authority().ok_or(TokenError::FixedSupply)?;
// SAFETY: `authority_info` is not currently borrowed.
unsafe { validate_owner(mint_authority, authority_info, remaining)? };
if let Some(authority) = new_authority {
mint.set_mint_authority(authority);
} else {
mint.clear_mint_authority();
}
}
AuthorityType::FreezeAccount => {
// Once a mint's freeze authority is disabled, it cannot be re-enabled by
// setting a new freeze_authority.
let freeze_authority = mint
.freeze_authority()
.ok_or(TokenError::MintCannotFreeze)?;
// SAFETY: `authority_info` is not currently borrowed.
unsafe { validate_owner(freeze_authority, authority_info, remaining)? };
if let Some(authority) = new_authority {
mint.set_freeze_authority(authority);
} else {
mint.clear_freeze_authority();
}
}
_ => {
return Err(TokenError::AuthorityTypeNotSupported.into());
}
}
} else {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}