// ACC-Collateral: 资产抵押协议(Collateral Protocol) // // NAC原生的资产抵押标准,用于借贷和DeFi应用 // 100% NAC原生协议,不是任何现有标准的实现 use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// 抵押状态 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum CollateralStatus { /// 活跃 Active, /// 已清算 Liquidated, /// 已释放 Released, /// 已违约 Defaulted, } /// 抵押率类型 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum CollateralRatioType { /// 初始抵押率(Initial LTV) Initial, /// 维持抵押率(Maintenance LTV) Maintenance, /// 清算抵押率(Liquidation LTV) Liquidation, } /// 抵押记录 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CollateralRecord { /// 抵押ID pub collateral_id: String, /// 抵押资产ID pub asset_id: String, /// 抵押人地址 pub borrower: String, /// 贷款人地址 pub lender: String, /// 抵押资产价值(USD,以分为单位) pub collateral_value: u128, /// 借款金额(USD,以分为单位) pub loan_amount: u128, /// 初始抵押率(百分比,如150表示150%) pub initial_ltv: u16, /// 维持抵押率(百分比) pub maintenance_ltv: u16, /// 清算抵押率(百分比) pub liquidation_ltv: u16, /// 当前抵押率(百分比) pub current_ltv: u16, /// 利率(年化,基点,如500表示5%) pub interest_rate: u16, /// 抵押状态 pub status: CollateralStatus, /// 创建时间 pub created_at: u64, /// 到期时间 pub expires_at: u64, /// 最后更新时间 pub updated_at: u64, /// 清算时间 pub liquidated_at: Option, } /// 抵押错误类型 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum CollateralError { /// 抵押记录不存在 RecordNotFound, /// 抵押记录已存在 RecordAlreadyExists, /// 资产不存在 AssetNotFound, /// 抵押率不足 InsufficientCollateral, /// 抵押已清算 AlreadyLiquidated, /// 抵押已释放 AlreadyReleased, /// 未到期 NotExpired, /// 未授权操作 Unauthorized, /// 无效的抵押率 InvalidLTV, } /// 抵押状态 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CollateralState { /// 抵押记录映射 (collateral_id -> CollateralRecord) pub collaterals: HashMap, /// 资产抵押映射 (asset_id -> collateral_id) pub asset_collaterals: HashMap, /// 借款人抵押列表 (borrower -> [collateral_ids]) pub borrower_collaterals: HashMap>, /// 贷款人抵押列表 (lender -> [collateral_ids]) pub lender_collaterals: HashMap>, } /// ACC-Collateral接口 pub trait ACCCollateral { /// 创建抵押 fn create_collateral(&mut self, record: CollateralRecord) -> Result<(), CollateralError>; /// 获取抵押记录 fn get_collateral(&self, collateral_id: &str) -> Result; /// 获取资产的抵押记录 fn get_asset_collateral(&self, asset_id: &str) -> Result; /// 更新抵押资产价值 fn update_collateral_value( &mut self, collateral_id: &str, new_value: u128, ) -> Result<(), CollateralError>; /// 计算当前抵押率 fn calculate_ltv(&self, collateral_id: &str) -> Result; /// 检查是否需要清算 fn is_liquidatable(&self, collateral_id: &str) -> bool; /// 清算抵押 fn liquidate(&mut self, collateral_id: &str) -> Result<(), CollateralError>; /// 释放抵押 fn release(&mut self, collateral_id: &str) -> Result<(), CollateralError>; /// 部分还款 fn partial_repay( &mut self, collateral_id: &str, amount: u128, ) -> Result<(), CollateralError>; /// 获取借款人的抵押列表 fn get_borrower_collaterals(&self, borrower: &str) -> Vec; /// 获取贷款人的抵押列表 fn get_lender_collaterals(&self, lender: &str) -> Vec; /// 获取所有需要清算的抵押 fn get_liquidatable_collaterals(&self) -> Vec; } /// ACC-Collateral标准实现 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CollateralToken { state: CollateralState, } impl CollateralToken { /// 创建新的抵押管理器 pub fn new() -> Self { Self { state: CollateralState { collaterals: HashMap::new(), asset_collaterals: HashMap::new(), borrower_collaterals: HashMap::new(), lender_collaterals: HashMap::new(), }, } } /// 获取状态的可变引用 pub fn state_mut(&mut self) -> &mut CollateralState { &mut self.state } /// 获取状态的不可变引用 pub fn state(&self) -> &CollateralState { &self.state } /// 验证抵押率 fn validate_ltv(&self, record: &CollateralRecord) -> Result<(), CollateralError> { // LTV应该是递增的:initial < maintenance < liquidation if record.initial_ltv > record.maintenance_ltv || record.maintenance_ltv > record.liquidation_ltv { return Err(CollateralError::InvalidLTV); } // 检查初始抵押率是否满足要求 let ltv = (record.loan_amount * 10000 / record.collateral_value) as u16; if ltv > record.initial_ltv { return Err(CollateralError::InsufficientCollateral); } Ok(()) } } impl Default for CollateralToken { fn default() -> Self { Self::new() } } impl ACCCollateral for CollateralToken { fn create_collateral(&mut self, mut record: CollateralRecord) -> Result<(), CollateralError> { // 检查抵押记录是否已存在 if self.state.collaterals.contains_key(&record.collateral_id) { return Err(CollateralError::RecordAlreadyExists); } // 检查资产是否已被抵押 if self.state.asset_collaterals.contains_key(&record.asset_id) { return Err(CollateralError::RecordAlreadyExists); } // 验证抵押率 self.validate_ltv(&record)?; let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); record.created_at = now; record.updated_at = now; record.status = CollateralStatus::Active; record.current_ltv = (record.loan_amount * 10000 / record.collateral_value) as u16; let collateral_id = record.collateral_id.clone(); let asset_id = record.asset_id.clone(); let borrower = record.borrower.clone(); let lender = record.lender.clone(); // 保存抵押记录 self.state .collaterals .insert(collateral_id.clone(), record); // 更新资产抵押映射 self.state .asset_collaterals .insert(asset_id, collateral_id.clone()); // 更新借款人抵押列表 self.state .borrower_collaterals .entry(borrower) .or_insert_with(Vec::new) .push(collateral_id.clone()); // 更新贷款人抵押列表 self.state .lender_collaterals .entry(lender) .or_insert_with(Vec::new) .push(collateral_id); Ok(()) } fn get_collateral(&self, collateral_id: &str) -> Result { self.state .collaterals .get(collateral_id) .cloned() .ok_or(CollateralError::RecordNotFound) } fn get_asset_collateral(&self, asset_id: &str) -> Result { let collateral_id = self .state .asset_collaterals .get(asset_id) .ok_or(CollateralError::AssetNotFound)?; self.get_collateral(collateral_id) } fn update_collateral_value( &mut self, collateral_id: &str, new_value: u128, ) -> Result<(), CollateralError> { let mut record = self.get_collateral(collateral_id)?; if record.status != CollateralStatus::Active { return Err(CollateralError::AlreadyLiquidated); } record.collateral_value = new_value; record.current_ltv = (record.loan_amount * 10000 / new_value) as u16; let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); record.updated_at = now; self.state .collaterals .insert(collateral_id.to_string(), record); Ok(()) } fn calculate_ltv(&self, collateral_id: &str) -> Result { let record = self.get_collateral(collateral_id)?; Ok((record.loan_amount * 10000 / record.collateral_value) as u16) } fn is_liquidatable(&self, collateral_id: &str) -> bool { if let Ok(record) = self.get_collateral(collateral_id) { record.status == CollateralStatus::Active && record.current_ltv >= record.liquidation_ltv } else { false } } fn liquidate(&mut self, collateral_id: &str) -> Result<(), CollateralError> { let mut record = self.get_collateral(collateral_id)?; if record.status != CollateralStatus::Active { return Err(CollateralError::AlreadyLiquidated); } if !self.is_liquidatable(collateral_id) { return Err(CollateralError::InsufficientCollateral); } let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); record.status = CollateralStatus::Liquidated; record.liquidated_at = Some(now); record.updated_at = now; self.state .collaterals .insert(collateral_id.to_string(), record); Ok(()) } fn release(&mut self, collateral_id: &str) -> Result<(), CollateralError> { let mut record = self.get_collateral(collateral_id)?; if record.status != CollateralStatus::Active { return Err(CollateralError::AlreadyReleased); } let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); record.status = CollateralStatus::Released; record.updated_at = now; self.state .collaterals .insert(collateral_id.to_string(), record); Ok(()) } fn partial_repay( &mut self, collateral_id: &str, amount: u128, ) -> Result<(), CollateralError> { let mut record = self.get_collateral(collateral_id)?; if record.status != CollateralStatus::Active { return Err(CollateralError::AlreadyLiquidated); } if amount > record.loan_amount { return Err(CollateralError::Unauthorized); } record.loan_amount -= amount; record.current_ltv = if record.loan_amount > 0 { (record.loan_amount * 10000 / record.collateral_value) as u16 } else { 0 }; let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); record.updated_at = now; self.state .collaterals .insert(collateral_id.to_string(), record); Ok(()) } fn get_borrower_collaterals(&self, borrower: &str) -> Vec { self.state .borrower_collaterals .get(borrower) .map(|collateral_ids| { collateral_ids .iter() .filter_map(|id| self.state.collaterals.get(id).cloned()) .collect() }) .unwrap_or_default() } fn get_lender_collaterals(&self, lender: &str) -> Vec { self.state .lender_collaterals .get(lender) .map(|collateral_ids| { collateral_ids .iter() .filter_map(|id| self.state.collaterals.get(id).cloned()) .collect() }) .unwrap_or_default() } fn get_liquidatable_collaterals(&self) -> Vec { self.state .collaterals .values() .filter(|record| { record.status == CollateralStatus::Active && record.current_ltv >= record.liquidation_ltv }) .cloned() .collect() } } #[cfg(test)] mod tests { use super::*; fn create_test_record() -> CollateralRecord { CollateralRecord { collateral_id: "COLL-001".to_string(), asset_id: "RWA-001".to_string(), borrower: "alice".to_string(), lender: "bob".to_string(), collateral_value: 1000000_00, // $10,000 loan_amount: 600000_00, // $6,000 initial_ltv: 7000, // 70% maintenance_ltv: 8000, // 80% liquidation_ltv: 8500, // 85% current_ltv: 6000, // 60% interest_rate: 500, // 5% status: CollateralStatus::Active, created_at: 0, expires_at: 1234567890 + 31536000, updated_at: 0, liquidated_at: None, } } #[test] fn test_create_collateral() { let mut collateral = CollateralToken::new(); let record = create_test_record(); assert!(collateral.create_collateral(record).is_ok()); } #[test] fn test_calculate_ltv() { let mut collateral = CollateralToken::new(); let record = create_test_record(); collateral.create_collateral(record).unwrap(); let ltv = collateral.calculate_ltv("COLL-001").unwrap(); assert_eq!(ltv, 6000); // 60% } #[test] fn test_update_collateral_value() { let mut collateral = CollateralToken::new(); let record = create_test_record(); collateral.create_collateral(record).unwrap(); assert!(collateral .update_collateral_value("COLL-001", 500000_00) .is_ok()); let ltv = collateral.calculate_ltv("COLL-001").unwrap(); assert_eq!(ltv, 12000); // 120% } #[test] fn test_liquidate() { let mut collateral = CollateralToken::new(); let record = create_test_record(); // 创建正常的抵押记录(LTV = 60%) collateral.create_collateral(record).unwrap(); // 通过降低抵押品价值使LTV上升到清算阈值以上 // 原始: loan_amount=600000_00, collateral_value=1000000_00, LTV=60% // 要达到90% LTV,需要: collateral_value = 600000_00 * 10000 / 9000 = 666666_67 assert!(collateral .update_collateral_value("COLL-001", 666666_67) .is_ok()); // 现在LTV应该是90%,超过liquidation_ltv (85%) assert!(collateral.liquidate("COLL-001").is_ok()); assert_eq!( collateral.get_collateral("COLL-001").unwrap().status, CollateralStatus::Liquidated ); } #[test] fn test_partial_repay() { let mut collateral = CollateralToken::new(); let record = create_test_record(); collateral.create_collateral(record).unwrap(); assert!(collateral.partial_repay("COLL-001", 100000_00).is_ok()); assert_eq!( collateral.get_collateral("COLL-001").unwrap().loan_amount, 500000_00 ); } }