diff --git a/contract/contracts/access-control/src/lib.rs b/contract/contracts/access-control/src/lib.rs index ab68cce..7e42530 100644 --- a/contract/contracts/access-control/src/lib.rs +++ b/contract/contracts/access-control/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] use predifi_errors::PrediFiError; -use soroban_sdk::{contract, contractimpl, contracttype, Address, Env}; +use soroban_sdk::{contract, contractevent, contractimpl, contracttype, Address, Env}; #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] @@ -12,31 +12,67 @@ pub enum Role { User = 4, } +#[contractevent(topics = ["admin_init"])] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AdminInitEvent { + pub admin: Address, +} + +#[contractevent(topics = ["role_assigned"])] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RoleAssignedEvent { + pub admin: Address, + pub user: Address, + pub role: Role, +} + +#[contractevent(topics = ["role_revoked"])] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RoleRevokedEvent { + pub admin: Address, + pub user: Address, + pub role: Role, +} + +#[contractevent(topics = ["role_transferred"])] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RoleTransferredEvent { + pub admin: Address, + pub from: Address, + pub to: Address, + pub role: Role, +} + +#[contractevent(topics = ["admin_transferred"])] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AdminTransferredEvent { + pub admin: Address, + pub new_admin: Address, +} + +#[contractevent(topics = ["all_roles_revoked"])] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AllRolesRevokedEvent { + pub admin: Address, + pub user: Address, +} + #[contracttype] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PoolStatus { - /// The pool is open for predictions. Active, - /// The event has occurred and the outcome is determined. Resolved, - /// The pool is closed for new predictions but not yet resolved. Closed, - /// The outcome is being disputed. Disputed, } #[contracttype] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PoolCategory { - /// Sports-related predictions. Sports, - /// Political predictions. Politics, - /// Financial predictions. Finance, - /// Entertainment predictions. Entertainment, - /// Other categories. Other, } @@ -53,31 +89,18 @@ pub struct AccessControl; #[contractimpl] impl AccessControl { - /// Initialize the contract with an initial admin address. - /// - /// # Arguments - /// * `admin` - The address to be appointed as the initial super admin. - /// - /// # Errors - /// * Panics with `"AlreadyInitializedOrConfigNotSet"` if the contract has already been initialized. pub fn init(env: Env, admin: Address) { if env.storage().instance().has(&DataKey::Admin) { soroban_sdk::panic_with_error!(&env, PrediFiError::AlreadyInitializedOrConfigNotSet); } env.storage().instance().set(&DataKey::Admin, &admin); - // Also grant the Admin role to the admin address. env.storage() .persistent() - .set(&DataKey::Role(admin, Role::Admin), &()); + .set(&DataKey::Role(admin.clone(), Role::Admin), &()); + + AdminInitEvent { admin }.publish(&env); } - /// Returns the current super admin address. - /// - /// # Returns - /// The address of the current super admin. - /// - /// # Errors - /// * Panics with `"NotInitialized"` if the contract hasn't been initialized yet. pub fn get_admin(env: Env) -> Address { env.storage() .instance() @@ -85,17 +108,6 @@ impl AccessControl { .expect("NotInitialized") } - /// Assigns a specific role to a user. - /// - /// Only the current super admin can call this function. - /// - /// # Arguments - /// * `admin_caller` - The address of the admin calling the function. - /// * `user` - The address to receive the role. - /// * `role` - The role to be assigned. - /// - /// # Errors - /// * `Unauthorized` - If the caller is not the super admin. pub fn assign_role( env: Env, admin_caller: Address, @@ -111,22 +123,17 @@ impl AccessControl { env.storage() .persistent() - .set(&DataKey::Role(user, role), &()); + .set(&DataKey::Role(user.clone(), role.clone()), &()); + + RoleAssignedEvent { + admin: admin_caller, + user, + role, + } + .publish(&env); Ok(()) } - /// Revokes a specific role from a user. - /// - /// Only the current super admin can call this function. - /// - /// # Arguments - /// * `admin_caller` - The address of the admin calling the function. - /// * `user` - The address from which the role will be revoked. - /// * `role` - The role to be revoked. - /// - /// # Errors - /// * `Unauthorized` - If the caller is not the super admin. - /// * `InsufficientPermissions` - If the user doesn't have the specified role. pub fn revoke_role( env: Env, admin_caller: Address, @@ -150,35 +157,21 @@ impl AccessControl { env.storage() .persistent() - .remove(&DataKey::Role(user, role)); + .remove(&DataKey::Role(user.clone(), role.clone())); + + RoleRevokedEvent { + admin: admin_caller, + user, + role, + } + .publish(&env); Ok(()) } - /// Checks if a user has a specific role. - /// - /// # Arguments - /// * `user` - The address to check. - /// * `role` - The role to check for. - /// - /// # Returns - /// `true` if the user has the role, `false` otherwise. pub fn has_role(env: Env, user: Address, role: Role) -> bool { env.storage().persistent().has(&DataKey::Role(user, role)) } - /// Transfers a role from one address to another. - /// - /// Only the current super admin can call this function. - /// - /// # Arguments - /// * `admin_caller` - The address of the admin calling the function. - /// * `from` - The address currently holding the role. - /// * `to` - The address to receive the role. - /// * `role` - The role to be transferred. - /// - /// # Errors - /// * `Unauthorized` - If the caller is not the super admin. - /// * `InsufficientPermissions` - If the `from` address doesn't have the specified role. pub fn transfer_role( env: Env, admin_caller: Address, @@ -203,23 +196,21 @@ impl AccessControl { env.storage() .persistent() - .remove(&DataKey::Role(from, role.clone())); + .remove(&DataKey::Role(from.clone(), role.clone())); env.storage() .persistent() - .set(&DataKey::Role(to, role), &()); + .set(&DataKey::Role(to.clone(), role.clone()), &()); + + RoleTransferredEvent { + admin: admin_caller, + from, + to, + role, + } + .publish(&env); Ok(()) } - /// Transfers the super admin status to a new address. - /// - /// Only the current super admin can call this function. - /// - /// # Arguments - /// * `admin_caller` - The address of the current admin. - /// * `new_admin` - The address to become the new super admin. - /// - /// # Errors - /// * `Unauthorized` - If the caller is not the current super admin. pub fn transfer_admin( env: Env, admin_caller: Address, @@ -232,27 +223,24 @@ impl AccessControl { return Err(PrediFiError::Unauthorized); } - // Update the admin address. env.storage().instance().set(&DataKey::Admin, &new_admin); - // Transfer the Admin role record. env.storage() .persistent() .remove(&DataKey::Role(current_admin, Role::Admin)); env.storage() .persistent() - .set(&DataKey::Role(new_admin, Role::Admin), &()); + .set(&DataKey::Role(new_admin.clone(), Role::Admin), &()); + + AdminTransferredEvent { + admin: admin_caller, + new_admin, + } + .publish(&env); Ok(()) } - /// Checks if a user is the current super admin. - /// - /// # Arguments - /// * `user` - The address to check. - /// - /// # Returns - /// `true` if the user is the current super admin, `false` otherwise. pub fn is_admin(env: Env, user: Address) -> bool { let stored: Option
= env.storage().instance().get(&DataKey::Admin); match stored { @@ -261,16 +249,6 @@ impl AccessControl { } } - /// Revokes all roles from a user. - /// - /// Only the current super admin can call this function. - /// - /// # Arguments - /// * `admin_caller` - The address of the admin calling the function. - /// * `user` - The address from which all roles will be revoked. - /// - /// # Errors - /// * `Unauthorized` - If the caller is not the super admin. pub fn revoke_all_roles( env: Env, admin_caller: Address, @@ -283,7 +261,6 @@ impl AccessControl { return Err(PrediFiError::Unauthorized); } - // Revoke all possible roles. for role in [ Role::Admin, Role::Operator, @@ -299,17 +276,15 @@ impl AccessControl { } } + AllRolesRevokedEvent { + admin: admin_caller, + user, + } + .publish(&env); + Ok(()) } - /// Checks if a user has any of the specified roles. - /// - /// # Arguments - /// * `user` - The address to check. - /// * `roles` - A vector of roles to check. - /// - /// # Returns - /// `true` if the user has at least one of the specified roles, `false` otherwise. pub fn has_any_role(env: Env, user: Address, roles: soroban_sdk::Vec