use super::events::*;
use crate::access::errors::Error;
use odra::prelude::*;
pub type Role = [u8; 32];
pub const DEFAULT_ADMIN_ROLE: Role = [0u8; 32];
#[odra::module(events = [RoleAdminChanged, RoleGranted, RoleRevoked], errors = Error)]
pub struct AccessControl {
roles: Mapping<(Role, Address), bool>,
role_admin: Mapping<Role, Role>
}
#[odra::module]
impl AccessControl {
pub fn has_role(&self, role: &Role, address: &Address) -> bool {
self.roles.get_or_default(&(*role, *address))
}
pub fn get_role_admin(&self, role: &Role) -> Role {
let admin_role = self.role_admin.get(role);
if let Some(admin) = admin_role {
admin
} else {
DEFAULT_ADMIN_ROLE
}
}
pub fn grant_role(&mut self, role: &Role, address: &Address) {
self.check_role(&self.get_role_admin(role), &self.env().caller());
self.unchecked_grant_role(role, address);
}
pub fn revoke_role(&mut self, role: &Role, address: &Address) {
self.check_role(&self.get_role_admin(role), &self.env().caller());
self.unchecked_revoke_role(role, address);
}
pub fn renounce_role(&mut self, role: &Role, address: &Address) {
if address != &self.env().caller() {
self.env().revert(Error::RoleRenounceForAnotherAddress);
}
self.unchecked_revoke_role(role, address);
}
}
impl AccessControl {
pub fn check_role(&self, role: &Role, address: &Address) {
if !self.has_role(role, address) {
self.env().revert(Error::MissingRole);
}
}
pub fn set_admin_role(&mut self, role: &Role, admin_role: &Role) {
let previous_admin_role = self.get_role_admin(role);
self.role_admin.set(role, *admin_role);
self.env().emit_event(RoleAdminChanged {
role: *role,
previous_admin_role,
new_admin_role: *admin_role
});
}
pub fn unchecked_grant_role(&mut self, role: &Role, address: &Address) {
if !self.has_role(role, address) {
self.roles.set(&(*role, *address), true);
self.env().emit_event(RoleGranted {
role: *role,
address: *address,
sender: self.env().caller()
});
}
}
pub fn unchecked_revoke_role(&mut self, role: &Role, address: &Address) {
if self.has_role(role, address) {
self.roles.set(&(*role, *address), false);
self.env().emit_event(RoleRevoked {
role: *role,
address: *address,
sender: self.env().caller()
});
}
}
}