types.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphavm library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 //! Governor Identity (GID) type definitions. 20 //! 21 //! This module defines the core types used by the GID program: 22 //! - [`GovernorStatus`] - The status of a governor (Active, Suspended, Removed) 23 //! - [`GovernorRecord`] - Complete record for a registered governor 24 //! 25 //! ## Type Aliases 26 //! 27 //! - `Address` - Reuses the address type from credits module 28 //! - `EncryptedMetadata` - Encrypted blob containing governor identity verification data 29 30 use crate::{credits::types::Address, types::AxAmount}; 31 use serde::{Deserialize, Serialize}; 32 33 /// Encrypted metadata blob for governor identity verification. 34 /// 35 /// In Phase 1, this is stored as raw bytes. The encryption scheme 36 /// and metadata format will be defined in later phases. 37 pub type EncryptedMetadata = Vec<u8>; 38 39 /// The status of a governor in the registry. 40 /// 41 /// Governors can transition through these states: 42 /// - `Active` -> `Suspended`: Governor privileges temporarily revoked 43 /// - `Suspended` -> `Active`: Governor privileges restored 44 /// - `Active` -> `Removed`: Governor permanently removed 45 /// - `Suspended` -> `Removed`: Governor permanently removed 46 /// 47 /// Note: Removal is permanent and cannot be reversed. 48 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] 49 pub enum GovernorStatus { 50 /// Governor is active and can perform mint operations. 51 #[default] 52 Active, 53 54 /// Governor is temporarily suspended and cannot mint. 55 /// 56 /// Suspension may be used during audits or investigations. 57 /// A suspended governor can be restored to Active status. 58 Suspended, 59 60 /// Governor has been permanently removed from the registry. 61 /// 62 /// Removal is irreversible. The governor's historical records 63 /// are retained for audit purposes, but they cannot perform 64 /// any operations. 65 Removed, 66 } 67 68 impl GovernorStatus { 69 /// Returns true if the governor can perform mint operations. 70 pub fn can_mint(&self) -> bool { 71 matches!(self, Self::Active) 72 } 73 74 /// Returns true if this status allows restoration to Active. 75 pub fn can_restore(&self) -> bool { 76 matches!(self, Self::Suspended) 77 } 78 79 /// Returns a human-readable name for the status. 80 pub fn name(&self) -> &'static str { 81 match self { 82 Self::Active => "active", 83 Self::Suspended => "suspended", 84 Self::Removed => "removed", 85 } 86 } 87 } 88 89 impl core::fmt::Display for GovernorStatus { 90 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 91 write!(f, "{}", self.name()) 92 } 93 } 94 95 /// A complete record for a registered governor. 96 /// 97 /// Governor records track all information about a governor including 98 /// their identity, registration time, current status, and cumulative 99 /// mint/burn statistics for audit purposes. 100 /// 101 /// ## Privacy 102 /// 103 /// The `metadata` field contains encrypted identity verification data. 104 /// In ZK mode, this data remains private and is only accessible to 105 /// authorized auditors with the appropriate decryption keys. 106 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] 107 pub struct GovernorRecord { 108 /// The blockchain address that identifies this governor. 109 /// 110 /// This is the public key / address used for signing mint operations. 111 pub address: Address, 112 113 /// Encrypted metadata blob containing identity verification data. 114 /// 115 /// This may include: 116 /// - KYC/AML verification hashes 117 /// - Organizational identifiers 118 /// - Authorization documentation references 119 /// 120 /// The encryption ensures privacy while allowing authorized audits. 121 pub metadata: EncryptedMetadata, 122 123 /// The block height at which this governor was registered. 124 /// 125 /// Used for audit trails and determining governor seniority. 126 pub registration_block: u64, 127 128 /// The current status of this governor. 129 pub status: GovernorStatus, 130 131 /// Cumulative amount of credits minted by this governor. 132 /// 133 /// This is a running total for audit purposes. It represents 134 /// all credits ever minted, not the current circulating amount. 135 pub cumulative_mint: AxAmount, 136 137 /// Cumulative amount of credits burned under this governor's authority. 138 /// 139 /// This tracks burns that were attributed to this governor, 140 /// useful for auditing net credit creation per governor. 141 pub cumulative_burn: AxAmount, 142 } 143 144 impl GovernorRecord { 145 /// Creates a new governor record with default values. 146 /// 147 /// The new governor is created in `Active` status with zero 148 /// cumulative mint/burn values. 149 /// 150 /// # Arguments 151 /// 152 /// * `address` - The blockchain address for this governor 153 /// * `metadata` - Encrypted identity verification data 154 /// * `registration_block` - The block height of registration 155 pub fn new(address: Address, metadata: EncryptedMetadata, registration_block: u64) -> Self { 156 Self { 157 address, 158 metadata, 159 registration_block, 160 status: GovernorStatus::Active, 161 cumulative_mint: AxAmount::ZERO, 162 cumulative_burn: AxAmount::ZERO, 163 } 164 } 165 166 /// Returns true if this governor can perform mint operations. 167 pub fn can_mint(&self) -> bool { 168 self.status.can_mint() 169 } 170 171 /// Returns the net credits created by this governor. 172 /// 173 /// This is `cumulative_mint - cumulative_burn`, representing 174 /// the net contribution to circulating supply. 175 /// 176 /// Returns `None` if cumulative_burn exceeds cumulative_mint 177 /// (which should not happen in normal operation). 178 pub fn net_mint(&self) -> Option<AxAmount> { 179 self.cumulative_mint.checked_sub(self.cumulative_burn) 180 } 181 182 /// Records a mint operation, updating cumulative_mint. 183 /// 184 /// Returns the new cumulative mint value, or `None` on overflow. 185 /// 186 /// # Arguments 187 /// 188 /// * `amount` - The amount minted in this operation 189 pub fn record_mint(&mut self, amount: AxAmount) -> Option<AxAmount> { 190 let new_total = self.cumulative_mint.checked_add(amount)?; 191 self.cumulative_mint = new_total; 192 Some(new_total) 193 } 194 195 /// Records a burn operation, updating cumulative_burn. 196 /// 197 /// Returns the new cumulative burn value, or `None` on overflow. 198 /// 199 /// # Arguments 200 /// 201 /// * `amount` - The amount burned in this operation 202 pub fn record_burn(&mut self, amount: AxAmount) -> Option<AxAmount> { 203 let new_total = self.cumulative_burn.checked_add(amount)?; 204 self.cumulative_burn = new_total; 205 Some(new_total) 206 } 207 208 /// Suspends this governor. 209 /// 210 /// Returns `true` if the suspension was successful (governor was Active). 211 /// Returns `false` if the governor was already Suspended or Removed. 212 pub fn suspend(&mut self) -> bool { 213 if self.status == GovernorStatus::Active { 214 self.status = GovernorStatus::Suspended; 215 true 216 } else { 217 false 218 } 219 } 220 221 /// Restores this governor to Active status. 222 /// 223 /// Returns `true` if the restoration was successful (governor was Suspended). 224 /// Returns `false` if the governor was Active or Removed. 225 pub fn restore(&mut self) -> bool { 226 if self.status.can_restore() { 227 self.status = GovernorStatus::Active; 228 true 229 } else { 230 false 231 } 232 } 233 234 /// Permanently removes this governor. 235 /// 236 /// Returns `true` if the removal was successful (governor was not already Removed). 237 /// Returns `false` if the governor was already Removed. 238 pub fn remove(&mut self) -> bool { 239 if self.status != GovernorStatus::Removed { 240 self.status = GovernorStatus::Removed; 241 true 242 } else { 243 false 244 } 245 } 246 } 247 248 impl Default for GovernorRecord { 249 fn default() -> Self { 250 Self { 251 address: String::new(), 252 metadata: Vec::new(), 253 registration_block: 0, 254 status: GovernorStatus::default(), 255 cumulative_mint: AxAmount::ZERO, 256 cumulative_burn: AxAmount::ZERO, 257 } 258 } 259 } 260 261 #[cfg(test)] 262 mod tests { 263 use super::*; 264 265 #[test] 266 fn test_governor_status_can_mint() { 267 assert!(GovernorStatus::Active.can_mint()); 268 assert!(!GovernorStatus::Suspended.can_mint()); 269 assert!(!GovernorStatus::Removed.can_mint()); 270 } 271 272 #[test] 273 fn test_governor_status_can_restore() { 274 assert!(!GovernorStatus::Active.can_restore()); 275 assert!(GovernorStatus::Suspended.can_restore()); 276 assert!(!GovernorStatus::Removed.can_restore()); 277 } 278 279 #[test] 280 fn test_governor_status_name() { 281 assert_eq!(GovernorStatus::Active.name(), "active"); 282 assert_eq!(GovernorStatus::Suspended.name(), "suspended"); 283 assert_eq!(GovernorStatus::Removed.name(), "removed"); 284 } 285 286 #[test] 287 fn test_governor_status_display() { 288 assert_eq!(format!("{}", GovernorStatus::Active), "active"); 289 assert_eq!(format!("{}", GovernorStatus::Suspended), "suspended"); 290 assert_eq!(format!("{}", GovernorStatus::Removed), "removed"); 291 } 292 293 #[test] 294 fn test_governor_record_new() { 295 let record = GovernorRecord::new("gov_addr_123".to_string(), vec![0x01, 0x02, 0x03], 1000); 296 297 assert_eq!(record.address, "gov_addr_123"); 298 assert_eq!(record.metadata, vec![0x01, 0x02, 0x03]); 299 assert_eq!(record.registration_block, 1000); 300 assert_eq!(record.status, GovernorStatus::Active); 301 assert!(record.cumulative_mint.is_zero()); 302 assert!(record.cumulative_burn.is_zero()); 303 assert!(record.can_mint()); 304 } 305 306 #[test] 307 fn test_governor_record_default() { 308 let record = GovernorRecord::default(); 309 assert!(record.address.is_empty()); 310 assert!(record.metadata.is_empty()); 311 assert_eq!(record.registration_block, 0); 312 assert_eq!(record.status, GovernorStatus::Active); 313 } 314 315 #[test] 316 fn test_governor_record_mint_operations() { 317 let mut record = GovernorRecord::new("gov".to_string(), vec![], 100); 318 319 // Record first mint 320 let result = record.record_mint(AxAmount::from_microcredits(50_000)); 321 assert_eq!(result, Some(AxAmount::from_microcredits(50_000))); 322 assert_eq!(record.cumulative_mint.to_microcredits(), 50_000); 323 324 // Record second mint 325 let result = record.record_mint(AxAmount::from_microcredits(30_000)); 326 assert_eq!(result, Some(AxAmount::from_microcredits(80_000))); 327 assert_eq!(record.cumulative_mint.to_microcredits(), 80_000); 328 } 329 330 #[test] 331 fn test_governor_record_burn_operations() { 332 let mut record = GovernorRecord::new("gov".to_string(), vec![], 100); 333 334 // Record mint first 335 record.record_mint(AxAmount::from_microcredits(100_000)); 336 337 // Record burn 338 let result = record.record_burn(AxAmount::from_microcredits(20_000)); 339 assert_eq!(result, Some(AxAmount::from_microcredits(20_000))); 340 assert_eq!(record.cumulative_burn.to_microcredits(), 20_000); 341 342 // Check net mint 343 assert_eq!(record.net_mint(), Some(AxAmount::from_microcredits(80_000))); 344 } 345 346 #[test] 347 fn test_governor_record_suspend_restore() { 348 let mut record = GovernorRecord::new("gov".to_string(), vec![], 100); 349 350 // Initially active 351 assert!(record.can_mint()); 352 353 // Suspend 354 assert!(record.suspend()); 355 assert!(!record.can_mint()); 356 assert_eq!(record.status, GovernorStatus::Suspended); 357 358 // Cannot suspend again 359 assert!(!record.suspend()); 360 361 // Restore 362 assert!(record.restore()); 363 assert!(record.can_mint()); 364 assert_eq!(record.status, GovernorStatus::Active); 365 366 // Cannot restore when active 367 assert!(!record.restore()); 368 } 369 370 #[test] 371 fn test_governor_record_remove() { 372 let mut record = GovernorRecord::new("gov".to_string(), vec![], 100); 373 374 // Remove from active 375 assert!(record.remove()); 376 assert!(!record.can_mint()); 377 assert_eq!(record.status, GovernorStatus::Removed); 378 379 // Cannot remove again 380 assert!(!record.remove()); 381 382 // Cannot restore after removal 383 assert!(!record.restore()); 384 } 385 386 #[test] 387 fn test_governor_record_remove_from_suspended() { 388 let mut record = GovernorRecord::new("gov".to_string(), vec![], 100); 389 390 record.suspend(); 391 assert!(record.remove()); 392 assert_eq!(record.status, GovernorStatus::Removed); 393 } 394 395 #[test] 396 fn test_governor_record_serde() { 397 let record = GovernorRecord::new("gov_addr".to_string(), vec![0xAB, 0xCD], 500); 398 399 let json = serde_json::to_string(&record).unwrap(); 400 let deserialized: GovernorRecord = serde_json::from_str(&json).unwrap(); 401 402 assert_eq!(record, deserialized); 403 } 404 405 #[test] 406 fn test_governor_record_net_mint_underflow() { 407 let mut record = GovernorRecord::new("gov".to_string(), vec![], 100); 408 409 // Simulate edge case where burn exceeds mint (shouldn't happen normally) 410 record.cumulative_mint = AxAmount::from_microcredits(50); 411 record.cumulative_burn = AxAmount::from_microcredits(100); 412 413 assert!(record.net_mint().is_none()); 414 } 415 }