1use soroban_sdk::{contracttype, Address, Env, Symbol};
2
3use super::error::StandardsError;
4
5const ROLE_MEMBER_PREFIX: &str = "std_role_m";
6const ROLE_ADMIN_PREFIX: &str = "std_role_a";
7
8pub const DEFAULT_ADMIN_ROLE_NAME: &str = "DEFAULT_ADMIN_ROLE";
9
10#[derive(Clone, Debug)]
12pub struct AccessControl {
13 id: Symbol,
14}
15
16#[contracttype]
17#[derive(Clone, Debug, Eq, PartialEq)]
18pub struct RoleGrantedEvent {
19 pub role: Symbol,
20 pub account: Address,
21 pub sender: Address,
22}
23
24#[contracttype]
25#[derive(Clone, Debug, Eq, PartialEq)]
26pub struct RoleRevokedEvent {
27 pub role: Symbol,
28 pub account: Address,
29 pub sender: Address,
30}
31
32#[contracttype]
33#[derive(Clone, Debug, Eq, PartialEq)]
34pub struct RoleAdminChangedEvent {
35 pub role: Symbol,
36 pub previous_admin_role: Symbol,
37 pub new_admin_role: Symbol,
38 pub sender: Address,
39}
40
41impl AccessControl {
42 pub fn new(id: Symbol) -> Self {
43 Self { id }
44 }
45
46 pub fn initialize(
47 &self,
48 env: &Env,
49 admin: &Address,
50 ) -> Result<RoleGrantedEvent, StandardsError> {
51 let default_admin_role = self.default_admin_role(env);
52 let admin_key = self.role_admin_key(env, &default_admin_role);
53 if env.storage().persistent().has(&admin_key) {
54 return Err(StandardsError::AlreadyInitialized);
55 }
56
57 env.storage()
58 .persistent()
59 .set(&admin_key, &default_admin_role);
60 self.grant_role_unchecked(env, &default_admin_role, admin);
61
62 Ok(RoleGrantedEvent {
63 role: default_admin_role,
64 account: admin.clone(),
65 sender: admin.clone(),
66 })
67 }
68
69 pub fn default_admin_role(&self, env: &Env) -> Symbol {
70 Symbol::new(env, DEFAULT_ADMIN_ROLE_NAME)
71 }
72
73 pub fn has_role(&self, env: &Env, role: &Symbol, account: &Address) -> bool {
74 env.storage()
75 .persistent()
76 .has(&self.role_member_key(env, role, account))
77 }
78
79 pub fn require_role(
80 &self,
81 env: &Env,
82 role: &Symbol,
83 account: &Address,
84 ) -> Result<(), StandardsError> {
85 if self.has_role(env, role, account) {
86 return Ok(());
87 }
88 Err(StandardsError::Unauthorized)
89 }
90
91 pub fn role_admin(&self, env: &Env, role: &Symbol) -> Symbol {
92 env.storage()
93 .persistent()
94 .get(&self.role_admin_key(env, role))
95 .unwrap_or_else(|| self.default_admin_role(env))
96 }
97
98 pub fn grant_role(
99 &self,
100 env: &Env,
101 caller: &Address,
102 role: &Symbol,
103 account: &Address,
104 ) -> Result<RoleGrantedEvent, StandardsError> {
105 let admin_role = self.role_admin(env, role);
106 self.require_role(env, &admin_role, caller)?;
107 if self.has_role(env, role, account) {
108 return Err(StandardsError::RoleAlreadyGranted);
109 }
110
111 self.grant_role_unchecked(env, role, account);
112 Ok(RoleGrantedEvent {
113 role: role.clone(),
114 account: account.clone(),
115 sender: caller.clone(),
116 })
117 }
118
119 pub fn revoke_role(
120 &self,
121 env: &Env,
122 caller: &Address,
123 role: &Symbol,
124 account: &Address,
125 ) -> Result<RoleRevokedEvent, StandardsError> {
126 let admin_role = self.role_admin(env, role);
127 self.require_role(env, &admin_role, caller)?;
128 if !self.has_role(env, role, account) {
129 return Err(StandardsError::RoleNotGranted);
130 }
131
132 env.storage()
133 .persistent()
134 .remove(&self.role_member_key(env, role, account));
135
136 Ok(RoleRevokedEvent {
137 role: role.clone(),
138 account: account.clone(),
139 sender: caller.clone(),
140 })
141 }
142
143 pub fn renounce_role(
144 &self,
145 env: &Env,
146 role: &Symbol,
147 caller: &Address,
148 ) -> Result<RoleRevokedEvent, StandardsError> {
149 if !self.has_role(env, role, caller) {
150 return Err(StandardsError::RoleNotGranted);
151 }
152
153 env.storage()
154 .persistent()
155 .remove(&self.role_member_key(env, role, caller));
156
157 Ok(RoleRevokedEvent {
158 role: role.clone(),
159 account: caller.clone(),
160 sender: caller.clone(),
161 })
162 }
163
164 pub fn set_role_admin(
165 &self,
166 env: &Env,
167 caller: &Address,
168 role: &Symbol,
169 new_admin_role: &Symbol,
170 ) -> Result<RoleAdminChangedEvent, StandardsError> {
171 let previous_admin_role = self.role_admin(env, role);
172 self.require_role(env, &previous_admin_role, caller)?;
173
174 env.storage()
175 .persistent()
176 .set(&self.role_admin_key(env, role), new_admin_role);
177
178 Ok(RoleAdminChangedEvent {
179 role: role.clone(),
180 previous_admin_role,
181 new_admin_role: new_admin_role.clone(),
182 sender: caller.clone(),
183 })
184 }
185
186 fn grant_role_unchecked(&self, env: &Env, role: &Symbol, account: &Address) {
187 env.storage()
188 .persistent()
189 .set(&self.role_member_key(env, role, account), &true);
190 }
191
192 fn role_member_key(
193 &self,
194 env: &Env,
195 role: &Symbol,
196 account: &Address,
197 ) -> (Symbol, Symbol, Symbol, Address) {
198 (
199 Symbol::new(env, ROLE_MEMBER_PREFIX),
200 self.id.clone(),
201 role.clone(),
202 account.clone(),
203 )
204 }
205
206 fn role_admin_key(&self, env: &Env, role: &Symbol) -> (Symbol, Symbol, Symbol) {
207 (
208 Symbol::new(env, ROLE_ADMIN_PREFIX),
209 self.id.clone(),
210 role.clone(),
211 )
212 }
213}