use crate::*; use near_sdk::log; impl Contract { // ==================== Internal Emergency Functions ==================== /// Emergency activation function to reset all role assignments to emergency accounts pub fn internal_emergency_role_settings(&mut self) { // revoke role for all roles from all accounts self.kernel_state.role_assignments.clear(); // grant role "owner" to all emergency accounts let emergency_accounts: Vec = self .emergency_config .emergency_accounts .iter() .cloned() .collect(); for account in emergency_accounts { self.internal_grant_role("owner".to_string(), RoleTarget::AccountId(account)); } log!("Emergency role settings activated: all roles cleared, emergency accounts granted owner role"); } /// Emergency activation function to reset all policies to owner role /// This provides a recovery mechanism in case of misconfiguration /// Uses pagination to handle large numbers of policies efficiently pub fn internal_emergency_policy_settings( &mut self, start_index: Option, end_index: Option, ) { // Use default values if not provided let start_index = start_index.unwrap_or(0); let end_index = end_index.unwrap_or(100); // Collect all policy IDs let policy_ids: Vec = self.kernel_state.policies.keys().cloned().collect(); // verify indices require!( start_index < end_index, "start_index must be less than end_index" ); require!(start_index < policy_ids.len(), "start_index out of bounds"); // Apply pagination to handle large policy sets let paginated_policy_ids = policy_ids .into_iter() .skip(start_index) .take(end_index - start_index); // Update each policy in the paginated range for policy_id in paginated_policy_ids { if let Some(policy) = self.kernel_state.policies.get_mut(&policy_id) { policy.required_role = "owner".to_string(); policy.required_vote_count = self.emergency_config.emergency_vote_threshold; } } log!( "Emergency policy settings activated for policies {} to {}: all policies set to owner role with vote count {}", start_index, end_index, self.emergency_config.emergency_vote_threshold ); } } #[near] impl Contract { // ==================== Public Emergency Functions ==================== /// Activate emergency mode after sufficient inactivity /// Requires sufficient active emergency votes from emergency accounts /// Optional params: start_index, end_index (limit policies), skip_role_reset pub fn start_emergency_mode(&mut self) { require!( self.emergency_config .emergency_accounts .contains(&env::predecessor_account_id()), "Only emergency accounts can execute emergency mode" ); let active_votes = self.get_active_emergency_votes(); require!( active_votes.len() as u32 >= self.emergency_config.emergency_vote_threshold, format!( "Insufficient emergency votes: {} of {} required", active_votes.len(), self.emergency_config.emergency_vote_threshold ) ); require!( self.is_kernel_inactive(), "Emergency mode cannot be activated yet: insufficient inactivity duration" ); // Execute emergency mode self.internal_emergency_role_settings(); self.internal_emergency_policy_settings(None, None); self.kernel_state.emergency_mode_active = true; near_sdk::log!("Emergency mode activated via voting threshold"); } /// Set policies to emergency mode within specified index range pub fn set_policies_to_emergency_mode(&mut self, start_index: usize, end_index: usize) { require!( self.emergency_config .emergency_accounts .contains(&env::predecessor_account_id()), "Only emergency accounts can execute emergency mode" ); require!( self.kernel_state.emergency_mode_active, "Emergency mode is not active; cannot set policies to emergency mode" ); self.internal_emergency_policy_settings(Some(start_index), Some(end_index)); near_sdk::log!( "Policies from index {} to {} set to emergency mode", start_index, end_index ); } /// Cast a vote for emergency mode activation /// Can only be called by emergency accounts /// Emergency accounts can vote even when kernel is still active pub fn vote_for_emergency_mode(&mut self) { let caller = env::predecessor_account_id(); // Validate caller is an emergency account require!( self.emergency_config.emergency_accounts.contains(&caller), "Only emergency accounts can vote for emergency mode" ); self.kernel_state.emergency_votes.insert( caller.clone(), Vote { proposal_id: 0, // Not used for emergency votes voter: caller.clone(), timestamp: U128(env::block_timestamp() as u128), }, ); near_sdk::log!( "Vote cast by {} for emergency vote. Votes: {}/{}", caller, self.get_active_emergency_votes().len(), self.emergency_config.emergency_vote_threshold ); } // ==================== Emergency Getter Functions ==================== pub fn get_emergency_inactive_duration_ns(&self) -> U128 { self.emergency_config.emergency_inactive_duration_ns } pub fn get_emergency_vote_threshold(&self) -> u32 { self.emergency_config.emergency_vote_threshold } pub fn get_emergency_vote_duration_ns(&self) -> U128 { self.emergency_config.emergency_vote_duration_ns } pub fn get_emergency_accounts(&self) -> Vec { self.emergency_config .emergency_accounts .iter() .cloned() .collect() } pub fn get_emergency_votes(&self) -> Vec { self.kernel_state .emergency_votes .iter() .map(|(_, vote)| vote.clone()) .collect() } pub fn is_kernel_inactive(&self) -> bool { let last_executed = self.kernel_state.last_executed_proposal_timestamp.0; let current_time = near_sdk::env::block_timestamp() as u128; current_time.checked_sub(last_executed).unwrap_or(0) >= self.emergency_config.emergency_inactive_duration_ns.0 } /// Get the current active emergency vote details pub fn get_active_emergency_votes(&self) -> Vec { let current_time = near_sdk::env::block_timestamp() as u128; // only get active votes by using current time and vote creation time self.kernel_state .emergency_votes .iter() .filter(|(_, vote)| { vote.timestamp.0 + self.emergency_config.emergency_vote_duration_ns.0 > current_time }) .map(|(_, vote)| vote.clone()) .collect() } }