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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
use crate::abi::Token;
use crate::{ensure, keccak_packed, Bytes32, Error, Zero};
/// Roles that are known at dev time.
pub enum StaticRole {
UnlimitedReaderRole,
NameSetterRole,
}
pub trait AccessControlRegistryAdminnedWithManager {
type Address: AsRef<[u8]> + Zero + PartialEq;
/// Get the manager of this registry
fn manager(&self) -> &Self::Address;
/// Admin role description
fn admin_role_description(&self) -> String;
/// Admin role description hash
fn admin_role_description_hash(&self) -> Bytes32;
/// Admin role
fn admin_role(&self) -> Bytes32;
}
/// The access control registry interface in the solidity contract
pub trait AccessControlRegistry: AccessControlRegistryAdminnedWithManager {
/// Default admin role, align with Openzepplin's definition
const DEFAULT_ADMIN_ROLE: Bytes32 = [0; 32];
const NAME_SETTER_ROLE_DESCRIPTION: &'static str = "Name setter";
const UNLIMITED_READER_ROLE_DESCRIPTION: &'static str = "Unlimited reader";
/// Find the role by its name. Not in the original solidity contract
/// Just for making it work in Rust
fn find_static_role(&self, role: StaticRole) -> Bytes32 {
match role {
StaticRole::UnlimitedReaderRole => self.derive_role(
self.derive_admin_role(self.manager()),
Self::UNLIMITED_READER_ROLE_DESCRIPTION.parse().unwrap(),
),
StaticRole::NameSetterRole => self.derive_role(
self.derive_admin_role(self.manager()),
Self::NAME_SETTER_ROLE_DESCRIPTION.parse().unwrap(),
),
}
}
/// Checks that an account has a specific role. Reverts
/// with a standardized message including the required role.
/// `role` The role to check
/// `msg_sender` The address to check
fn only_role(&self, role: &Bytes32, msg_sender: &Self::Address) -> Result<(), Error> {
ensure!(
self.has_role(
&self.get_role_admin(role).ok_or(Error::RoleAdminNotFound)?,
msg_sender
),
Error::NotAuthorized
)
}
/// Checks if user has a particular role
/// `role` The role to check
/// `who` The address to check
fn has_role(&self, role: &Bytes32, who: &Self::Address) -> bool;
/// Grant role for the user
/// `role` The role to grant
/// `who` The address to grant role
fn grant_role(&mut self, role: &Bytes32, who: &Self::Address) -> Result<(), Error>;
/// Get the admin role of role
/// `role` The role to check
fn get_role_admin(&self, role: &Bytes32) -> Option<Bytes32>;
/// Set the role admin for a role
/// `role` The role to grant
/// `role_admin` The role admin
fn set_role_admin(&mut self, role: &Bytes32, role_admin: Bytes32) -> Result<(), Error>;
/// Called by the account to renounce the role
/// Override to disallow managers to renounce their root roles.
/// `role` Role to be renounced
/// `account` Account to renounce the role
fn renounce_role(&mut self, role: &Bytes32, account: &Self::Address) -> Result<(), Error>;
/// Called by the role admin to renounce the role
/// Override to disallow managers to renounce their root roles.
/// `role` Role to be renounced
/// `account` Account to renounce the role
fn revoke_role(&mut self, role: &Bytes32, account: &Self::Address) -> Result<(), Error>;
/// Initializes the manager by initializing its root role and
/// granting it to them
/// Anyone can initialize a manager. An uninitialized manager
/// attempting to initialize a role will be initialized automatically.
/// Once a manager is initialized, subsequent initializations have no
/// effect.
/// `manager` Manager address to be initialized
fn initialize_manager(&mut self, manager: &Self::Address) -> Result<(), Error> {
ensure!(!manager.is_zero(), Error::InvalidAddress)?;
let root_role = RoleDeriver::derive_root_role(manager.as_ref());
if !self.has_role(&root_role, manager) {
self.grant_role(&root_role, manager)?;
}
Ok(())
}
/// Initializes a role by setting its admin role and grants it to
/// the sender
/// If the sender should not have the initialized role, they should
/// explicitly renounce it after initializing it.
/// Once a role is initialized, subsequent initializations have no effect
/// other than granting the role to the sender.
/// The sender must be a member of `admin_role`. `admin_role` value is not
/// validated because the sender cannot have the `bytes32(0)` role.
/// If the sender is an uninitialized manager that is initializing a role
/// directly under their root role, manager initialization will happen
/// automatically, which will grant the sender `admin_role` and allow them
/// to initialize the role.
/// `admin_role` Admin role to be assigned to the initialized role
/// `description` Human-readable description of the initialized role
/// `msg_sender` The message sender address
fn initialize_role_and_grant_to_sender(
&mut self,
admin_role: Bytes32,
description: String,
msg_sender: &Self::Address,
) -> Result<Bytes32, Error> {
ensure!(!description.is_empty(), Error::RoleDescriptionEmpty)?;
let role = self.derive_role(admin_role, description);
// AccessControl roles have `DEFAULT_ADMIN_ROLE` (i.e., `bytes32(0)`)
// as their `admin_role` by default. No account in AccessControlRegistry
// can possibly have that role, which means all initialized roles will
// have non-default admin roles, and vice versa.
if self.get_role_admin(&role) == Some(Self::DEFAULT_ADMIN_ROLE) {
if admin_role == self.derive_root_role(msg_sender) {
self.initialize_manager(msg_sender)?;
}
self.set_role_admin(&role, admin_role)?;
}
self.grant_role(&role, msg_sender)?;
Ok(role)
}
/// Derives the admin role of the manager
/// `manager` Manager address
fn derive_admin_role(&self, manager: &Self::Address) -> Bytes32 {
self.derive_role(
self.derive_root_role(manager),
self.admin_role_description(),
)
}
/// Derives the root role of the manager
/// `manager` Manager address
fn derive_root_role(&self, manager: &Self::Address) -> Bytes32 {
RoleDeriver::derive_root_role(manager.as_ref())
}
/// Derives the role using its admin role and description
///
/// This implies that roles adminned by the same role cannot have the
/// same description
/// `admin_role` Admin role
/// `description` Human-readable description of the role
fn derive_role(&self, admin_role: Bytes32, description: String) -> Bytes32 {
RoleDeriver::derive_role(admin_role, description)
}
}
/// Contract that implements the AccessControlRegistry role derivation logic
///
/// If a contract interfaces with AccessControlRegistry and needs to
/// derive roles, it should inherit this contract instead of re-implementing
/// the logic
pub struct RoleDeriver;
impl RoleDeriver {
/// Derives the root role of the manager
/// `manager` Manager address
/// `rootRole` Root role
pub fn derive_root_role(manager: &[u8]) -> Bytes32 {
keccak_packed(&[Token::FixedBytes(manager.to_vec())])
}
/// Derives the role using its admin role and description
///
/// This implies that roles adminned by the same role cannot have the
/// same description
/// `admin_role` Admin role
/// `description` Human-readable description of the role
pub fn derive_role(admin_role: Bytes32, description: String) -> Bytes32 {
Self::derive_role_with_hash(admin_role, keccak_packed(&[Token::String(description)]))
}
/// Derives the role using its admin role and description hash
///
/// This implies that roles adminned by the same role cannot have the
/// same description
/// `admin_role` Admin role
/// `description` Hash of the human-readable description of the role
pub fn derive_role_with_hash(admin_role: Bytes32, description_hash: Bytes32) -> Bytes32 {
keccak_packed(&[
Token::FixedBytes(admin_role.to_vec()),
Token::FixedBytes(description_hash.to_vec()),
])
}
}
#[cfg(test)]
mod tests {}