NAC_Blockchain/nac-udm/src/l1_protocol/acc/acc_redemption.rs

167 lines
7.5 KiB
Rust

//! 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<Timestamp>,
pub constitutional_receipt: Hash,
pub rejection_reason: Option<String>,
}
#[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<Hash, RedemptionRequest>,
pub redemption_fund: HashMap<Hash, u128>,
pub redemption_window_open: bool,
pub pending_events: Vec<RedemptionProtocolEvent>,
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<Hash, ACCRedemptionError> {
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(&timestamp.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<u128, ACCRedemptionError> {
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<RedemptionProtocolEvent> { 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()
}
}