//! acc_redemption - NAC 原生协议实现 //! 从 acc_remaining_protocols.rs 提取 use crate::primitives::{Address, Hash, Timestamp}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum ACCRedemptionError { RedemptionNotFound(Hash), InsufficientRedemptionFund { available: u128, requested: u128 }, RedemptionWindowClosed, InvalidConstitutionalReceipt, Unauthorized(Address), RedemptionAlreadyProcessed(Hash), } impl std::fmt::Display for ACCRedemptionError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::RedemptionNotFound(h) => write!(f, "赎回请求不存在: {}", h.to_hex()), Self::InsufficientRedemptionFund { available, requested } => write!(f, "赎回资金不足: 可用 {},请求 {}", available, requested), Self::RedemptionWindowClosed => write!(f, "赎回窗口已关闭"), Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"), Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()), Self::RedemptionAlreadyProcessed(h) => write!(f, "赎回请求已处理: {}", h.to_hex()), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum RedemptionStatus { Pending, Processing, Completed, Rejected, Cancelled } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RedemptionRequest { pub redemption_id: Hash, pub asset_id: Hash, pub redeemer: Address, pub amount: u128, pub redemption_price_xtzh: u128, pub total_redemption_xtzh: u128, pub status: RedemptionStatus, pub requested_at: Timestamp, pub processed_at: Option, pub constitutional_receipt: Hash, pub rejection_reason: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum RedemptionProtocolEvent { RedemptionRequested { redemption_id: Hash, asset_id: Hash, redeemer: Address, amount: u128, timestamp: Timestamp }, RedemptionCompleted { redemption_id: Hash, total_xtzh: u128, timestamp: Timestamp }, RedemptionRejected { redemption_id: Hash, reason: String, timestamp: Timestamp }, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ACCRedemptionProtocol { pub protocol_uid: String, pub lens_protocol_vector: String, pub requests: HashMap, pub redemption_fund: HashMap, pub redemption_window_open: bool, pub pending_events: Vec, pub created_at: Timestamp, pub updated_at: Timestamp, } impl ACCRedemptionProtocol { pub fn new() -> Self { Self { protocol_uid: "nac.acc.ACCRedemptionProtocol.v1".to_string(), lens_protocol_vector: "ACC-Redemption".to_string(), requests: HashMap::new(), redemption_fund: HashMap::new(), redemption_window_open: true, pending_events: Vec::new(), created_at: Timestamp::now(), updated_at: Timestamp::now(), } } pub fn fund_redemption_pool(&mut self, asset_id: Hash, amount_xtzh: u128, constitutional_receipt: Hash) -> Result<(), ACCRedemptionError> { if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); } *self.redemption_fund.entry(asset_id).or_insert(0) += amount_xtzh; Ok(()) } pub fn request_redemption( &mut self, asset_id: Hash, redeemer: Address, amount: u128, redemption_price_xtzh: u128, constitutional_receipt: Hash, timestamp: Timestamp, ) -> Result { if !self.redemption_window_open { return Err(ACCRedemptionError::RedemptionWindowClosed); } let total = amount.saturating_mul(redemption_price_xtzh); let available = self.redemption_fund.get(&asset_id).copied().unwrap_or(0); if available < total { return Err(ACCRedemptionError::InsufficientRedemptionFund { available, requested: total }); } let mut data = Vec::new(); data.extend_from_slice(asset_id.as_bytes()); data.extend_from_slice(redeemer.as_bytes()); data.extend_from_slice(×tamp.as_secs().to_be_bytes()); let redemption_id = Hash::sha3_384(&data); let request = RedemptionRequest { redemption_id, asset_id, redeemer: redeemer.clone(), amount, redemption_price_xtzh, total_redemption_xtzh: total, status: RedemptionStatus::Pending, requested_at: timestamp.clone(), processed_at: None, constitutional_receipt, rejection_reason: None, }; self.requests.insert(redemption_id, request); self.pending_events.push(RedemptionProtocolEvent::RedemptionRequested { redemption_id, asset_id, redeemer, amount, timestamp }); self.updated_at = Timestamp::now(); Ok(redemption_id) } pub fn complete_redemption(&mut self, redemption_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp) -> Result { if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); } let request = self.requests.get_mut(&redemption_id).ok_or(ACCRedemptionError::RedemptionNotFound(redemption_id))?; if request.status != RedemptionStatus::Pending { return Err(ACCRedemptionError::RedemptionAlreadyProcessed(redemption_id)); } let total = request.total_redemption_xtzh; let asset_id = request.asset_id; if let Some(fund) = self.redemption_fund.get_mut(&asset_id) { *fund = fund.saturating_sub(total); } request.status = RedemptionStatus::Completed; request.processed_at = Some(timestamp.clone()); self.pending_events.push(RedemptionProtocolEvent::RedemptionCompleted { redemption_id, total_xtzh: total, timestamp }); Ok(total) } pub fn get_request(&self, id: &Hash) -> Option<&RedemptionRequest> { self.requests.get(id) } pub fn drain_pending_events(&mut self) -> Vec { std::mem::take(&mut self.pending_events) } } impl ACCRedemptionProtocol { /// 取消赎回申请 pub fn cancel_redemption( &mut self, redemption_id: &Hash, requester: &Address, constitutional_receipt: Hash, timestamp: Timestamp, ) -> Result<(), ACCRedemptionError> { if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); } let req = self.requests.get_mut(redemption_id) .ok_or(ACCRedemptionError::RedemptionNotFound(redemption_id.clone()))?; if &req.redeemer != requester { return Err(ACCRedemptionError::Unauthorized(requester.clone())); } req.status = RedemptionStatus::Cancelled; req.processed_at = Some(timestamp); Ok(()) } /// 获取待处理申请列表 pub fn get_pending_requests(&self) -> Vec<&RedemptionRequest> { self.requests.values() .filter(|r| r.status == RedemptionStatus::Pending) .collect() } /// 获取赎回池余额 pub fn get_pool_balance(&self, asset_id: &Hash) -> u128 { self.redemption_fund.get(asset_id).copied().unwrap_or(0) } /// 获取所有申请(按资产) pub fn get_requests_by_asset(&self, asset_id: &Hash) -> Vec<&RedemptionRequest> { self.requests.values() .filter(|r| &r.asset_id == asset_id) .collect() } /// 获取申请总数 pub fn total_requests(&self) -> usize { self.requests.len() } }