NAC_Blockchain/_archive/standalone_acc_protocols/nac-acc-1400/src/compliance.rs

847 lines
26 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 合规验证系统
//!
//! 实现投资者资格验证、持有限额检查、地域限制和监管报告生成
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<u64>,
/// 净资产
pub net_worth: Option<u64>,
/// 是否为专业投资者
pub is_professional: bool,
/// 资格认证时间
pub certified_at: u64,
/// 资格过期时间
pub expires_at: Option<u64>,
/// 认证机构
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<InvestorType>,
/// 是否启用
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<String>,
/// 是否启用
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<String>,
/// 验证时间
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<String>,
/// 警告项
pub warnings: Vec<String>,
}
/// 持有人信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HolderInfo {
/// 账户地址
pub account: String,
/// 持有数量
pub amount: u64,
/// 持有占比(百分比)
pub percentage: u8,
}
/// 合规验证系统
#[derive(Debug)]
pub struct ComplianceSystem {
/// 投资者资格
qualifications: HashMap<String, InvestorQualification>,
/// 持有限额配置
holding_limits: HashMap<String, HoldingLimit>,
/// 地域限制
geo_restrictions: HashMap<String, GeographicRestriction>,
/// 投资者地域信息
investor_locations: HashMap<String, InvestorLocation>,
/// 监管报告
reports: HashMap<String, RegulatoryReport>,
/// 持有人信息
holders: HashMap<[u8; 32], Vec<HolderInfo>>, // 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<u64>,
net_worth: Option<u64>,
is_professional: bool,
certifier: String,
expires_at: Option<u64>,
) -> 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<InvestorType>,
) -> 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<HolderInfo>) {
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>,
) -> 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<String>,
) {
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<InvestorType>,
) -> 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<String, String> {
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::<Vec<_>>(),
});
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<InvestorType, usize> = 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::<Vec<_>>(),
});
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<String, usize> = 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::<Vec<_>>(),
});
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);
}
}