use crate::helpers::event::{RoleGranted, RoleRevoked}; use crate::permission::types::*; use crate::{StorageKey, *}; use near_sdk::AccountId; #[near] impl Contract { /// Get all roles for a specific target pub fn get_roles_for_target(&self, target: RoleTarget) -> Vec { if let Some(roles) = self.kernel_state.role_assignments.get(&target) { roles.iter().map(|role| role.0.clone()).collect() } else { Vec::new() } } /// Get effective roles for an account (includes both direct account roles and agent codehash roles) pub fn get_effective_roles_for_account(&self, account_id: AccountId) -> Vec { let mut all_roles = std::collections::HashSet::new(); // Get direct account roles let account_target = RoleTarget::AccountId(account_id.clone()); if let Some(account_roles) = self.kernel_state.role_assignments.get(&account_target) { for role in account_roles.iter() { all_roles.insert(role.0.clone()); } } // Check if account is a registered agent and get codehash roles if let Some(agent) = self .kernel_state .registered_agent_by_account_id .get(&account_id) { let codehash_target = RoleTarget::Codehash(Codehash::from(agent.codehash.clone())); if let Some(codehash_roles) = self.kernel_state.role_assignments.get(&codehash_target) { for role in codehash_roles.iter() { all_roles.insert(role.0.clone()); } } } let mut roles_vec: Vec = all_roles.into_iter().collect(); roles_vec.sort(); roles_vec } /// Get all targets (AccountIds and Codehashes) that have a specific role pub fn get_targets_with_role(&self, role_name: String) -> Vec { let mut targets = Vec::new(); let target_role = Role(role_name); for (target, roles_set) in self.kernel_state.role_assignments.iter() { if roles_set.contains(&target_role) { targets.push(target.clone()); } } targets } /// Get all accounts (including agents) that have a specific role pub fn get_accounts_with_role(&self, role_name: String) -> Vec { let mut accounts = Vec::new(); let target_role = Role(role_name.clone()); // Direct account roles for (target, roles_set) in self.kernel_state.role_assignments.iter() { if roles_set.contains(&target_role) { match target { RoleTarget::AccountId(account_id) => { accounts.push(account_id.clone()); } RoleTarget::Codehash(codehash) => { // Find all agents with this codehash for (agent_account, agent) in self.kernel_state.registered_agent_by_account_id.iter() { if agent.codehash == codehash.0 { accounts.push(agent_account.clone()); } } } } } } accounts.sort(); accounts.dedup(); accounts } /// Count total number of role targets (both AccountIds and Codehashes) pub fn get_role_targets_count(&self) -> u64 { self.kernel_state.role_assignments.len() as u64 } pub fn get_all_role_assignments(&self) -> Vec<(RoleTarget, Vec)> { let mut assignments = Vec::new(); for (target, roles_set) in self.kernel_state.role_assignments.iter() { let roles: Vec = roles_set.iter().map(|role| role.0.clone()).collect(); assignments.push((target.clone(), roles)); } assignments } } impl Contract { pub fn internal_grant_role(&mut self, role_id: String, target: RoleTarget) { let roles = self .kernel_state .role_assignments .entry(target.clone()) .or_insert_with(|| { IterableSet::new(StorageKey::RoleSet { target_hash: near_sdk::env::sha256(format!("{}", target).as_bytes()), }) }); roles.insert(Role(role_id.clone())); // Emit role granted event RoleGranted { target: &target, role: &role_id, } .emit(); } pub fn internal_revoke_role(&mut self, role_id: String, target: RoleTarget) { // Check if target exists and remove role, tracking if set becomes empty let is_empty = if let Some(roles) = self.kernel_state.role_assignments.get_mut(&target) { let role_to_remove = Role(role_id.clone()); roles.remove(&role_to_remove); roles.is_empty() } else { return; // Target doesn't exist, nothing to revoke }; // Remove the target entirely if no roles remain if is_empty { self.kernel_state.role_assignments.remove(&target); } // Emit role revoked event RoleRevoked { target: &target, role: &role_id, } .emit(); } pub fn internal_has_role(&self, account_id: &AccountId, role: &str) -> bool { // Check direct account roles first let account_target = RoleTarget::AccountId(account_id.clone()); if self.internal_has_role_via_target(&account_target, role) { return true; } // If account is a registered agent, check codehash roles if let Some(agent) = self .kernel_state .registered_agent_by_account_id .get(account_id) { let codehash_target = RoleTarget::Codehash(Codehash::from(agent.codehash.clone())); return self.internal_has_role_via_target(&codehash_target, role); } false } /// Check if a specific target has a role pub fn internal_has_role_via_target(&self, target: &RoleTarget, role: &str) -> bool { if let Some(roles) = self.kernel_state.role_assignments.get(target) { let role_to_check = Role(role.to_string()); roles.contains(&role_to_check) } else { false } } }