// Collateral Lending System // 资产抵押借贷系统 - RWA资产抵押借XTZH use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// 贷款状态 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum LoanStatus { Active, // 活跃 Repaid, // 已还款 Liquidated, // 已清算 Defaulted, // 违约 } /// 贷款记录 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Loan { /// 贷款ID pub loan_id: String, /// 借款人 pub borrower: String, /// 抵押资产TOKEN ID pub collateral_asset_id: String, /// 抵押份额数量 pub collateral_amount: u128, /// 抵押资产估值(XTZH) pub collateral_value: u128, /// 借款金额(XTZH) pub loan_amount: u128, /// 年利率(基点,如500=5%) pub interest_rate: u16, /// 抵押率(基点,如15000=150%) pub ltv_ratio: u16, /// 创建时间 pub created_at: u64, /// 到期时间 pub due_date: u64, /// 已还本金 pub repaid_principal: u128, /// 已还利息 pub repaid_interest: u128, /// 状态 pub status: LoanStatus, } impl Loan { /// 计算应付利息 pub fn calculate_interest(&self, current_time: u64) -> u128 { if current_time <= self.created_at { return 0; } let time_elapsed = current_time - self.created_at; let years = time_elapsed as u128 * 1_000_000_000_000_000_000 / (365 * 24 * 3600); let outstanding = self.loan_amount - self.repaid_principal; (outstanding * self.interest_rate as u128 * years) / (10000 * 1_000_000_000_000_000_000) } /// 计算总应还金额 pub fn calculate_total_due(&self, current_time: u64) -> u128 { let interest = self.calculate_interest(current_time); let outstanding_principal = self.loan_amount - self.repaid_principal; outstanding_principal + interest - self.repaid_interest } /// 计算当前健康度(抵押价值/贷款价值) pub fn calculate_health_factor(&self, current_collateral_value: u128) -> u128 { if self.loan_amount == 0 { return u128::MAX; } (current_collateral_value * 10000) / self.loan_amount } /// 是否需要清算 pub fn needs_liquidation(&self, current_collateral_value: u128, liquidation_threshold: u16) -> bool { let health_factor = self.calculate_health_factor(current_collateral_value); health_factor < liquidation_threshold as u128 } } /// 抵押借贷系统 pub struct CollateralLendingSystem { /// 贷款记录 (loan_id -> Loan) loans: HashMap, /// 用户XTZH余额 xtzh_balances: HashMap, /// 用户资产份额 (user, asset_id) -> shares asset_shares: HashMap<(String, String), u128>, /// 资产估值 (asset_id -> value in XTZH) asset_valuations: HashMap, /// 系统参数 params: LendingParams, /// 统计信息 stats: LendingStats, } /// 借贷参数 #[derive(Debug, Clone)] pub struct LendingParams { /// 最大抵押率(基点,如7500=75%) pub max_ltv: u16, /// 清算阈值(基点,如12000=120%) pub liquidation_threshold: u16, /// 清算奖励(基点,如500=5%) pub liquidation_bonus: u16, /// 默认年利率(基点) pub default_interest_rate: u16, } impl Default for LendingParams { fn default() -> Self { Self { max_ltv: 7500, // 75% liquidation_threshold: 12000, // 120% liquidation_bonus: 500, // 5% default_interest_rate: 800, // 8% } } } /// 借贷统计 #[derive(Debug, Clone, Default)] pub struct LendingStats { /// 总贷款数 pub total_loans: u64, /// 活跃贷款数 pub active_loans: u64, /// 总借出金额 pub total_lent: u128, /// 总抵押价值 pub total_collateral_value: u128, /// 总清算次数 pub total_liquidations: u64, } impl CollateralLendingSystem { /// 创建新系统 pub fn new(params: LendingParams) -> Self { Self { loans: HashMap::new(), xtzh_balances: HashMap::new(), asset_shares: HashMap::new(), asset_valuations: HashMap::new(), params, stats: LendingStats::default(), } } /// 设置XTZH余额 pub fn set_xtzh_balance(&mut self, user: String, amount: u128) { self.xtzh_balances.insert(user, amount); } /// 获取XTZH余额 pub fn get_xtzh_balance(&self, user: &str) -> u128 { *self.xtzh_balances.get(user).unwrap_or(&0) } /// 设置资产份额 pub fn set_asset_shares(&mut self, user: String, asset_id: String, shares: u128) { self.asset_shares.insert((user, asset_id), shares); } /// 获取资产份额 pub fn get_asset_shares(&self, user: &str, asset_id: &str) -> u128 { *self.asset_shares.get(&(user.to_string(), asset_id.to_string())).unwrap_or(&0) } /// 设置资产估值 pub fn set_asset_valuation(&mut self, asset_id: String, value: u128) { self.asset_valuations.insert(asset_id, value); } /// 获取资产估值 pub fn get_asset_valuation(&self, asset_id: &str) -> u128 { *self.asset_valuations.get(asset_id).unwrap_or(&0) } /// 创建贷款 pub fn create_loan( &mut self, borrower: String, collateral_asset_id: String, collateral_amount: u128, loan_amount: u128, duration_days: u64, ) -> Result { // 验证抵押品 let asset_shares = self.get_asset_shares(&borrower, &collateral_asset_id); if asset_shares < collateral_amount { return Err(format!("Insufficient collateral: {} < {}", asset_shares, collateral_amount)); } // 获取抵押品估值 let unit_value = self.get_asset_valuation(&collateral_asset_id); if unit_value == 0 { return Err("Asset valuation not available".to_string()); } let collateral_value = unit_value * collateral_amount; // 验证抵押率 let ltv = (loan_amount * 10000) / collateral_value; if ltv > self.params.max_ltv as u128 { return Err(format!("LTV too high: {}% > {}%", ltv / 100, self.params.max_ltv / 100)); } let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("mainnet: handle error") .as_secs(); let loan_id = format!("loan_{}_{}", borrower, now); let due_date = now + duration_days * 24 * 3600; // 锁定抵押品 self.set_asset_shares( borrower.clone(), collateral_asset_id.clone(), asset_shares - collateral_amount, ); // 发放贷款 let xtzh_balance = self.get_xtzh_balance(&borrower); self.set_xtzh_balance(borrower.clone(), xtzh_balance + loan_amount); // 创建贷款记录 let loan = Loan { loan_id: loan_id.clone(), borrower, collateral_asset_id, collateral_amount, collateral_value, loan_amount, interest_rate: self.params.default_interest_rate, ltv_ratio: ltv as u16, created_at: now, due_date, repaid_principal: 0, repaid_interest: 0, status: LoanStatus::Active, }; self.loans.insert(loan_id.clone(), loan); self.stats.total_loans += 1; self.stats.active_loans += 1; self.stats.total_lent += loan_amount; self.stats.total_collateral_value += collateral_value; Ok(loan_id) } /// 还款 pub fn repay_loan( &mut self, loan_id: &str, amount: u128, ) -> Result<(), String> { // 先收集需要的数据 let (borrower, collateral_asset_id, collateral_amount) = { let loan = self.loans.get(loan_id).ok_or("Loan not found")?; if loan.status != LoanStatus::Active { return Err("Loan is not active".to_string()); } let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("mainnet: handle error") .as_secs(); let total_due = loan.calculate_total_due(now); if amount > total_due { return Err(format!("Amount exceeds total due: {} > {}", amount, total_due)); } // 验证余额 let xtzh_balance = self.get_xtzh_balance(&loan.borrower); if xtzh_balance < amount { return Err(format!("Insufficient XTZH: {} < {}", xtzh_balance, amount)); } (loan.borrower.clone(), loan.collateral_asset_id.clone(), loan.collateral_amount) }; // 扣除还款 let xtzh_balance = self.get_xtzh_balance(&borrower); self.set_xtzh_balance(borrower.clone(), xtzh_balance - amount); // 更新贷款记录 let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("mainnet: handle error") .as_secs(); let loan = self.loans.get_mut(loan_id).expect("mainnet: handle error"); let interest_due = loan.calculate_interest(now) - loan.repaid_interest; if amount >= interest_due { // 先还利息,再还本金 loan.repaid_interest += interest_due; loan.repaid_principal += amount - interest_due; } else { // 只还利息 loan.repaid_interest += amount; } // 检查是否全部还清 if loan.repaid_principal >= loan.loan_amount { loan.status = LoanStatus::Repaid; self.stats.active_loans -= 1; // 归还抵押品 let asset_shares = self.get_asset_shares(&borrower, &collateral_asset_id); self.set_asset_shares( borrower, collateral_asset_id, asset_shares + collateral_amount, ); } Ok(()) } /// 清算贷款 pub fn liquidate_loan( &mut self, loan_id: &str, liquidator: String, ) -> Result { // 先收集所有需要的数据 let (collateral_asset_id, collateral_amount, liquidation_amount) = { let loan = self.loans.get(loan_id).ok_or("Loan not found")?; if loan.status != LoanStatus::Active { return Err("Loan is not active".to_string()); } // 获取当前抵押品价值 let unit_value = self.get_asset_valuation(&loan.collateral_asset_id); let current_collateral_value = unit_value * loan.collateral_amount; // 检查是否需要清算 if !loan.needs_liquidation(current_collateral_value, self.params.liquidation_threshold) { return Err("Loan is healthy, cannot liquidate".to_string()); } let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("mainnet: handle error") .as_secs(); let total_due = loan.calculate_total_due(now); // 计算清算金额(含奖励) let liquidation_amount = total_due + (total_due * self.params.liquidation_bonus as u128 / 10000); (loan.collateral_asset_id.clone(), loan.collateral_amount, liquidation_amount) }; // 验证清算人余额 let liquidator_balance = self.get_xtzh_balance(&liquidator); if liquidator_balance < liquidation_amount { return Err(format!("Insufficient XTZH for liquidation: {} < {}", liquidator_balance, liquidation_amount)); } // 扣除清算人XTZH self.set_xtzh_balance(liquidator.clone(), liquidator_balance - liquidation_amount); // 转移抵押品给清算人 let liquidator_shares = self.get_asset_shares(&liquidator, &collateral_asset_id); self.set_asset_shares( liquidator, collateral_asset_id, liquidator_shares + collateral_amount, ); // 更新贷款状态 let loan = self.loans.get_mut(loan_id).expect("mainnet: handle error"); loan.status = LoanStatus::Liquidated; self.stats.active_loans -= 1; self.stats.total_liquidations += 1; Ok(liquidation_amount) } /// 获取贷款 pub fn get_loan(&self, loan_id: &str) -> Option<&Loan> { self.loans.get(loan_id) } /// 获取统计信息 pub fn get_stats(&self) -> &LendingStats { &self.stats } /// 获取参数 pub fn get_params(&self) -> &LendingParams { &self.params } } impl Default for CollateralLendingSystem { fn default() -> Self { Self::new(LendingParams::default()) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_create_loan() { let mut system = CollateralLendingSystem::default(); system.set_asset_shares("borrower".to_string(), "asset1".to_string(), 100); system.set_asset_valuation("asset1".to_string(), 1_000_000_000_000_000_000_000); let loan_id = system.create_loan( "borrower".to_string(), "asset1".to_string(), 10, 7_000_000_000_000_000_000_000, 365, ).expect("mainnet: handle error"); assert!(system.get_loan(&loan_id).is_some()); assert_eq!(system.stats.total_loans, 1); assert_eq!(system.stats.active_loans, 1); } #[test] fn test_repay_loan() { let mut system = CollateralLendingSystem::default(); system.set_asset_shares("borrower".to_string(), "asset1".to_string(), 100); system.set_asset_valuation("asset1".to_string(), 1_000_000_000_000_000_000_000); let loan_id = system.create_loan( "borrower".to_string(), "asset1".to_string(), 10, 7_000_000_000_000_000_000_000, 365, ).expect("mainnet: handle error"); let loan_amount = system.get_loan(&loan_id).expect("mainnet: handle error").loan_amount; system.repay_loan(&loan_id, loan_amount).expect("mainnet: handle error"); let loan = system.get_loan(&loan_id).expect("mainnet: handle error"); assert_eq!(loan.status, LoanStatus::Repaid); } #[test] fn test_liquidation() { let mut system = CollateralLendingSystem::default(); system.set_asset_shares("borrower".to_string(), "asset1".to_string(), 100); system.set_asset_valuation("asset1".to_string(), 1_000_000_000_000_000_000_000); let loan_id = system.create_loan( "borrower".to_string(), "asset1".to_string(), 10, 7_000_000_000_000_000_000_000, 365, ).expect("mainnet: handle error"); // 抵押品价值下跌 system.set_asset_valuation("asset1".to_string(), 500_000_000_000_000_000_000); system.set_xtzh_balance("liquidator".to_string(), 10_000_000_000_000_000_000_000); let result = system.liquidate_loan(&loan_id, "liquidator".to_string()); assert!(result.is_ok()); assert_eq!(system.stats.total_liquidations, 1); } #[test] fn test_health_factor() { let mut system = CollateralLendingSystem::default(); system.set_asset_shares("borrower".to_string(), "asset1".to_string(), 100); system.set_asset_valuation("asset1".to_string(), 1_000_000_000_000_000_000_000); let loan_id = system.create_loan( "borrower".to_string(), "asset1".to_string(), 10, 7_000_000_000_000_000_000_000, 365, ).expect("mainnet: handle error"); let loan = system.get_loan(&loan_id).expect("mainnet: handle error"); let health_factor = loan.calculate_health_factor(10_000_000_000_000_000_000_000); // 健康度应该是 10000/7000 * 10000 = 14285 assert!(health_factor > 14000 && health_factor < 15000); } }