//! 合规验证系统 //! //! 实现投资者资格验证、持有限额检查、地域限制和监管报告生成 use std::collections::HashMap; use serde::{Serialize, Deserialize}; /// 投资者类型 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum InvestorType { /// 零售投资者 Retail, /// 认可投资者 Accredited, /// 合格投资者 Qualified, /// 机构投资者 Institutional, } /// 投资者资格 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InvestorQualification { /// 账户地址 pub account: String, /// 投资者类型 pub investor_type: InvestorType, /// 年收入(用于资格验证) pub annual_income: Option, /// 净资产 pub net_worth: Option, /// 是否为专业投资者 pub is_professional: bool, /// 资格认证时间 pub certified_at: u64, /// 资格过期时间 pub expires_at: Option, /// 认证机构 pub certifier: String, } /// 持有限额配置 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HoldingLimit { /// 限额ID pub id: String, /// 限额名称 pub name: String, /// 限额类型 pub limit_type: LimitType, /// 限额值 pub limit_value: u64, /// 适用的投资者类型 pub applies_to: Vec, /// 是否启用 pub enabled: bool, } /// 限额类型 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum LimitType { /// 单个账户持有上限 MaxHoldingPerAccount, /// 单个账户持有下限 MinHoldingPerAccount, /// 单次购买上限 MaxPurchaseAmount, /// 总持有人数上限 MaxHolderCount, /// 单个持有人占比上限(百分比) MaxOwnershipPercentage, } /// 地域限制 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GeographicRestriction { /// 限制ID pub id: String, /// 限制类型 pub restriction_type: GeoRestrictionType, /// 国家/地区代码列表 pub regions: Vec, /// 是否启用 pub enabled: bool, } /// 地域限制类型 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum GeoRestrictionType { /// 白名单(仅允许列表中的地区) Whitelist, /// 黑名单(禁止列表中的地区) Blacklist, } /// 投资者地域信息 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InvestorLocation { /// 账户地址 pub account: String, /// 国家代码 pub country_code: String, /// 州/省代码 pub state_code: Option, /// 验证时间 pub verified_at: u64, } /// 监管报告类型 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum ReportType { /// 持有人报告 HolderReport, /// 交易报告 TransactionReport, /// 合规状态报告 ComplianceStatusReport, /// 投资者分类报告 InvestorClassificationReport, /// 地域分布报告 GeographicDistributionReport, } /// 监管报告 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RegulatoryReport { /// 报告ID pub id: String, /// 报告类型 pub report_type: ReportType, /// 生成时间 pub generated_at: u64, /// 报告期间开始 pub period_start: u64, /// 报告期间结束 pub period_end: u64, /// 报告数据(JSON格式) pub data: String, /// 生成者 pub generated_by: String, } /// 合规检查结果 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ComplianceCheckResult { /// 是否合规 pub compliant: bool, /// 违规项 pub violations: Vec, /// 警告项 pub warnings: Vec, } /// 持有人信息 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HolderInfo { /// 账户地址 pub account: String, /// 持有数量 pub amount: u64, /// 持有占比(百分比) pub percentage: u8, } /// 合规验证系统 #[derive(Debug)] pub struct ComplianceSystem { /// 投资者资格 qualifications: HashMap, /// 持有限额配置 holding_limits: HashMap, /// 地域限制 geo_restrictions: HashMap, /// 投资者地域信息 investor_locations: HashMap, /// 监管报告 reports: HashMap, /// 持有人信息 holders: HashMap<[u8; 32], Vec>, // security_id -> holders /// 下一个限额ID next_limit_id: u64, /// 下一个限制ID next_restriction_id: u64, /// 下一个报告ID next_report_id: u64, } impl ComplianceSystem { /// 创建新的合规验证系统 pub fn new() -> Self { Self { qualifications: HashMap::new(), holding_limits: HashMap::new(), geo_restrictions: HashMap::new(), investor_locations: HashMap::new(), reports: HashMap::new(), holders: HashMap::new(), next_limit_id: 1, next_restriction_id: 1, next_report_id: 1, } } /// 设置投资者资格 pub fn set_investor_qualification( &mut self, account: String, investor_type: InvestorType, annual_income: Option, net_worth: Option, is_professional: bool, certifier: String, expires_at: Option, ) -> Result<(), String> { // 验证资格要求 match investor_type { InvestorType::Accredited => { // 认可投资者需要满足收入或净资产要求 let income_qualified = annual_income.map_or(false, |i| i >= 200_000); let net_worth_qualified = net_worth.map_or(false, |n| n >= 1_000_000); if !income_qualified && !net_worth_qualified { return Err("Accredited investor requirements not met".to_string()); } } InvestorType::Qualified => { // 合格投资者需要更高的要求 let income_qualified = annual_income.map_or(false, |i| i >= 300_000); let net_worth_qualified = net_worth.map_or(false, |n| n >= 2_000_000); if !income_qualified && !net_worth_qualified { return Err("Qualified investor requirements not met".to_string()); } } InvestorType::Institutional => { // 机构投资者需要专业认证 if !is_professional { return Err("Institutional investor must be professional".to_string()); } } InvestorType::Retail => { // 零售投资者无特殊要求 } } let qualification = InvestorQualification { account: account.clone(), investor_type, annual_income, net_worth, is_professional, certified_at: Self::current_timestamp(), expires_at, certifier, }; self.qualifications.insert(account, qualification); Ok(()) } /// 检查投资者资格 pub fn check_investor_qualification( &self, account: &str, required_type: InvestorType, ) -> Result<(), String> { let qual = self.qualifications.get(account) .ok_or_else(|| "Investor qualification not found".to_string())?; // 检查是否过期 if let Some(expires_at) = qual.expires_at { if Self::current_timestamp() > expires_at { return Err("Investor qualification has expired".to_string()); } } // 检查投资者类型等级 let type_level = |t: InvestorType| match t { InvestorType::Retail => 0, InvestorType::Accredited => 1, InvestorType::Qualified => 2, InvestorType::Institutional => 3, }; if type_level(qual.investor_type) < type_level(required_type) { return Err(format!( "Investor type {:?} is below required type {:?}", qual.investor_type, required_type )); } Ok(()) } /// 添加持有限额 pub fn add_holding_limit( &mut self, name: String, limit_type: LimitType, limit_value: u64, applies_to: Vec, ) -> String { let id = format!("LIMIT-{:08}", self.next_limit_id); self.next_limit_id += 1; let limit = HoldingLimit { id: id.clone(), name, limit_type, limit_value, applies_to, enabled: true, }; self.holding_limits.insert(id.clone(), limit); id } /// 启用/禁用持有限额 pub fn set_limit_enabled(&mut self, limit_id: &str, enabled: bool) -> Result<(), String> { let limit = self.holding_limits.get_mut(limit_id) .ok_or_else(|| "Holding limit not found".to_string())?; limit.enabled = enabled; Ok(()) } /// 更新持有人信息 pub fn update_holders(&mut self, security_id: [u8; 32], holders: Vec) { self.holders.insert(security_id, holders); } /// 检查持有限额 pub fn check_holding_limits( &self, account: &str, security_id: &[u8; 32], new_amount: u64, total_supply: u64, ) -> Result<(), String> { let investor_type = self.qualifications.get(account) .map(|q| q.investor_type) .unwrap_or(InvestorType::Retail); for limit in self.holding_limits.values() { if !limit.enabled { continue; } // 检查是否适用于该投资者类型 if !limit.applies_to.is_empty() && !limit.applies_to.contains(&investor_type) { continue; } match limit.limit_type { LimitType::MaxHoldingPerAccount => { if new_amount > limit.limit_value { return Err(format!( "Holding amount {} exceeds maximum {}", new_amount, limit.limit_value )); } } LimitType::MinHoldingPerAccount => { if new_amount > 0 && new_amount < limit.limit_value { return Err(format!( "Holding amount {} is below minimum {}", new_amount, limit.limit_value )); } } LimitType::MaxPurchaseAmount => { // 这个检查应该在购买时进行 // 这里简化处理 } LimitType::MaxHolderCount => { if let Some(holders) = self.holders.get(security_id) { let current_count = holders.len(); let is_new_holder = !holders.iter().any(|h| h.account == account); if is_new_holder && current_count >= limit.limit_value as usize { return Err(format!( "Maximum holder count {} reached", limit.limit_value )); } } } LimitType::MaxOwnershipPercentage => { if total_supply > 0 { let percentage = (new_amount * 100) / total_supply; if percentage > limit.limit_value { return Err(format!( "Ownership percentage {}% exceeds maximum {}%", percentage, limit.limit_value )); } } } } } Ok(()) } /// 添加地域限制 pub fn add_geographic_restriction( &mut self, restriction_type: GeoRestrictionType, regions: Vec, ) -> String { let id = format!("GEO-{:08}", self.next_restriction_id); self.next_restriction_id += 1; let restriction = GeographicRestriction { id: id.clone(), restriction_type, regions, enabled: true, }; self.geo_restrictions.insert(id.clone(), restriction); id } /// 设置投资者地域信息 pub fn set_investor_location( &mut self, account: String, country_code: String, state_code: Option, ) { let location = InvestorLocation { account: account.clone(), country_code, state_code, verified_at: Self::current_timestamp(), }; self.investor_locations.insert(account, location); } /// 检查地域限制 pub fn check_geographic_restrictions(&self, account: &str) -> Result<(), String> { let location = self.investor_locations.get(account) .ok_or_else(|| "Investor location not found".to_string())?; for restriction in self.geo_restrictions.values() { if !restriction.enabled { continue; } let is_in_list = restriction.regions.contains(&location.country_code); match restriction.restriction_type { GeoRestrictionType::Whitelist => { if !is_in_list { return Err(format!( "Country {} is not in whitelist", location.country_code )); } } GeoRestrictionType::Blacklist => { if is_in_list { return Err(format!( "Country {} is blacklisted", location.country_code )); } } } } Ok(()) } /// 执行完整的合规检查 pub fn perform_compliance_check( &self, account: &str, security_id: &[u8; 32], amount: u64, total_supply: u64, required_investor_type: Option, ) -> ComplianceCheckResult { let mut violations = Vec::new(); let mut warnings = Vec::new(); // 检查投资者资格 if let Some(required_type) = required_investor_type { if let Err(e) = self.check_investor_qualification(account, required_type) { violations.push(format!("Investor qualification: {}", e)); } } // 检查持有限额 if let Err(e) = self.check_holding_limits(account, security_id, amount, total_supply) { violations.push(format!("Holding limit: {}", e)); } // 检查地域限制 if let Err(e) = self.check_geographic_restrictions(account) { violations.push(format!("Geographic restriction: {}", e)); } // 检查资格是否即将过期 if let Some(qual) = self.qualifications.get(account) { if let Some(expires_at) = qual.expires_at { let current_time = Self::current_timestamp(); let days_until_expiry = (expires_at - current_time) / 86400; if days_until_expiry < 30 { warnings.push(format!( "Investor qualification expires in {} days", days_until_expiry )); } } } ComplianceCheckResult { compliant: violations.is_empty(), violations, warnings, } } /// 生成持有人报告 pub fn generate_holder_report( &mut self, security_id: &[u8; 32], generated_by: String, ) -> Result { let holders = self.holders.get(security_id) .ok_or_else(|| "No holder information found".to_string())?; let report_data = serde_json::json!({ "security_id": format!("{:?}", security_id), "total_holders": holders.len(), "holders": holders.iter().map(|h| { serde_json::json!({ "account": h.account, "amount": h.amount, "percentage": h.percentage, }) }).collect::>(), }); let report_id = format!("REPORT-{:08}", self.next_report_id); self.next_report_id += 1; let current_time = Self::current_timestamp(); let report = RegulatoryReport { id: report_id.clone(), report_type: ReportType::HolderReport, generated_at: current_time, period_start: current_time, period_end: current_time, data: report_data.to_string(), generated_by, }; self.reports.insert(report_id.clone(), report); Ok(report_id) } /// 生成投资者分类报告 pub fn generate_investor_classification_report( &mut self, generated_by: String, ) -> String { let mut classification_counts: HashMap = HashMap::new(); for qual in self.qualifications.values() { *classification_counts.entry(qual.investor_type).or_insert(0) += 1; } let report_data = serde_json::json!({ "total_investors": self.qualifications.len(), "classification": classification_counts.iter().map(|(t, c)| { serde_json::json!({ "type": format!("{:?}", t), "count": c, }) }).collect::>(), }); let report_id = format!("REPORT-{:08}", self.next_report_id); self.next_report_id += 1; let current_time = Self::current_timestamp(); let report = RegulatoryReport { id: report_id.clone(), report_type: ReportType::InvestorClassificationReport, generated_at: current_time, period_start: current_time, period_end: current_time, data: report_data.to_string(), generated_by, }; self.reports.insert(report_id.clone(), report); report_id } /// 生成地域分布报告 pub fn generate_geographic_distribution_report( &mut self, generated_by: String, ) -> String { let mut country_counts: HashMap = HashMap::new(); for location in self.investor_locations.values() { *country_counts.entry(location.country_code.clone()).or_insert(0) += 1; } let report_data = serde_json::json!({ "total_locations": self.investor_locations.len(), "distribution": country_counts.iter().map(|(country, count)| { serde_json::json!({ "country": country, "count": count, }) }).collect::>(), }); let report_id = format!("REPORT-{:08}", self.next_report_id); self.next_report_id += 1; let current_time = Self::current_timestamp(); let report = RegulatoryReport { id: report_id.clone(), report_type: ReportType::GeographicDistributionReport, generated_at: current_time, period_start: current_time, period_end: current_time, data: report_data.to_string(), generated_by, }; self.reports.insert(report_id.clone(), report); report_id } /// 获取报告 pub fn get_report(&self, report_id: &str) -> Option<&RegulatoryReport> { self.reports.get(report_id) } /// 获取所有报告 pub fn get_all_reports(&self) -> Vec<&RegulatoryReport> { self.reports.values().collect() } /// 获取投资者资格 pub fn get_investor_qualification(&self, account: &str) -> Option<&InvestorQualification> { self.qualifications.get(account) } /// 获取所有持有限额 pub fn get_all_holding_limits(&self) -> Vec<&HoldingLimit> { self.holding_limits.values().collect() } /// 获取所有地域限制 pub fn get_all_geographic_restrictions(&self) -> Vec<&GeographicRestriction> { self.geo_restrictions.values().collect() } /// 获取当前时间戳 fn current_timestamp() -> u64 { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("mainnet: handle error") .as_secs() } } impl Default for ComplianceSystem { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_investor_qualification() { let mut system = ComplianceSystem::new(); // 设置认可投资者 let result = system.set_investor_qualification( "investor1".to_string(), InvestorType::Accredited, Some(250_000), Some(1_500_000), false, "certifier1".to_string(), None, ); assert!(result.is_ok()); // 检查资格 assert!(system.check_investor_qualification("investor1", InvestorType::Retail).is_ok()); assert!(system.check_investor_qualification("investor1", InvestorType::Accredited).is_ok()); assert!(system.check_investor_qualification("investor1", InvestorType::Qualified).is_err()); } #[test] fn test_holding_limits() { let mut system = ComplianceSystem::new(); let security_id = [1u8; 32]; // 添加持有上限 system.add_holding_limit( "Max Holding".to_string(), LimitType::MaxHoldingPerAccount, 10000, vec![], ); // 检查限额 assert!(system.check_holding_limits("investor1", &security_id, 5000, 100000).is_ok()); assert!(system.check_holding_limits("investor1", &security_id, 15000, 100000).is_err()); } #[test] fn test_geographic_restrictions() { let mut system = ComplianceSystem::new(); // 添加白名单 system.add_geographic_restriction( GeoRestrictionType::Whitelist, vec!["US".to_string(), "UK".to_string()], ); // 设置投资者位置 system.set_investor_location( "investor1".to_string(), "US".to_string(), Some("CA".to_string()), ); system.set_investor_location( "investor2".to_string(), "CN".to_string(), None, ); // 检查限制 assert!(system.check_geographic_restrictions("investor1").is_ok()); assert!(system.check_geographic_restrictions("investor2").is_err()); } #[test] fn test_compliance_check() { let mut system = ComplianceSystem::new(); let security_id = [1u8; 32]; // 设置投资者 system.set_investor_qualification( "investor1".to_string(), InvestorType::Accredited, Some(250_000), None, false, "certifier1".to_string(), None, ).expect("mainnet: handle error"); system.set_investor_location( "investor1".to_string(), "US".to_string(), None, ); // 添加限制 system.add_holding_limit( "Max".to_string(), LimitType::MaxHoldingPerAccount, 10000, vec![], ); system.add_geographic_restriction( GeoRestrictionType::Whitelist, vec!["US".to_string()], ); // 执行合规检查 let result = system.perform_compliance_check( "investor1", &security_id, 5000, 100000, Some(InvestorType::Accredited), ); assert!(result.compliant); assert!(result.violations.is_empty()); } #[test] fn test_generate_reports() { let mut system = ComplianceSystem::new(); let security_id = [1u8; 32]; // 添加持有人信息 let holders = vec![ HolderInfo { account: "investor1".to_string(), amount: 1000, percentage: 50, }, HolderInfo { account: "investor2".to_string(), amount: 1000, percentage: 50, }, ]; system.update_holders(security_id, holders); // 生成持有人报告 let report_id = system.generate_holder_report(&security_id, "admin".to_string()).expect("mainnet: handle error"); let report = system.get_report(&report_id).expect("mainnet: handle error"); assert_eq!(report.report_type, ReportType::HolderReport); // 生成投资者分类报告 system.set_investor_qualification( "investor1".to_string(), InvestorType::Retail, None, None, false, "certifier1".to_string(), None, ).expect("mainnet: handle error"); let report_id = system.generate_investor_classification_report("admin".to_string()); let report = system.get_report(&report_id).expect("mainnet: handle error"); assert_eq!(report.report_type, ReportType::InvestorClassificationReport); } }