NAC_Blockchain/nvm_v2/acc-protocol/src/acc_redemption.rs

520 lines
15 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.

// ACC-Redemption: 资产赎回协议Redemption Protocol
//
// NAC原生的资产赎回标准用于资产退出机制
// 100% NAC原生协议不是任何现有标准的实现
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// 赎回状态
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RedemptionStatus {
/// 待审核
Pending,
/// 已批准
Approved,
/// 处理中
Processing,
/// 已完成
Completed,
/// 已拒绝
Rejected,
/// 已取消
Cancelled,
}
/// 赎回类型
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RedemptionType {
/// 全额赎回
Full,
/// 部分赎回
Partial,
/// 提前赎回
Early,
/// 到期赎回
Maturity,
}
/// 赎回请求
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RedemptionRequest {
/// 赎回ID
pub redemption_id: String,
/// 资产ID
pub asset_id: String,
/// 赎回人地址
pub redeemer: String,
/// 赎回类型
pub redemption_type: RedemptionType,
/// 赎回数量
pub amount: u128,
/// 赎回价格USD以分为单位
pub redemption_price: u128,
/// 赎回状态
pub status: RedemptionStatus,
/// 请求时间
pub requested_at: u64,
/// 批准时间
pub approved_at: Option<u64>,
/// 完成时间
pub completed_at: Option<u64>,
/// 预期完成时间
pub expected_completion: u64,
/// 提前赎回费率基点如100表示1%
pub early_redemption_fee: Option<u16>,
/// 实际费用
pub actual_fee: Option<u128>,
/// 审核备注
pub notes: Vec<String>,
}
/// 赎回错误类型
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RedemptionError {
/// 赎回请求不存在
RequestNotFound,
/// 赎回请求已存在
RequestAlreadyExists,
/// 资产不存在
AssetNotFound,
/// 赎回金额不足
InsufficientAmount,
/// 赎回已完成
AlreadyCompleted,
/// 赎回已取消
AlreadyCancelled,
/// 未授权操作
Unauthorized,
/// 赎回窗口未开放
RedemptionWindowClosed,
/// 提前赎回费用过高
EarlyRedemptionFeeTooHigh,
}
/// 赎回状态
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RedemptionState {
/// 赎回请求映射 (redemption_id -> RedemptionRequest)
pub redemptions: HashMap<String, RedemptionRequest>,
/// 资产赎回历史 (asset_id -> [redemption_ids])
pub asset_redemptions: HashMap<String, Vec<String>>,
/// 赎回人赎回列表 (redeemer -> [redemption_ids])
pub redeemer_redemptions: HashMap<String, Vec<String>>,
}
/// ACC-Redemption接口
pub trait ACCRedemption {
/// 提交赎回请求
fn submit_redemption(&mut self, request: RedemptionRequest) -> Result<(), RedemptionError>;
/// 获取赎回请求
fn get_redemption(&self, redemption_id: &str) -> Result<RedemptionRequest, RedemptionError>;
/// 获取资产的赎回历史
fn get_asset_redemptions(&self, asset_id: &str) -> Vec<RedemptionRequest>;
/// 批准赎回请求
fn approve_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError>;
/// 拒绝赎回请求
fn reject_redemption(
&mut self,
redemption_id: &str,
reason: String,
) -> Result<(), RedemptionError>;
/// 开始处理赎回
fn process_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError>;
/// 完成赎回
fn complete_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError>;
/// 取消赎回请求
fn cancel_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError>;
/// 计算赎回费用
fn calculate_redemption_fee(&self, redemption_id: &str) -> Result<u128, RedemptionError>;
/// 更新赎回状态
fn update_status(
&mut self,
redemption_id: &str,
status: RedemptionStatus,
) -> Result<(), RedemptionError>;
/// 获取赎回人的赎回列表
fn get_redeemer_redemptions(&self, redeemer: &str) -> Vec<RedemptionRequest>;
/// 添加审核备注
fn add_note(&mut self, redemption_id: &str, note: String) -> Result<(), RedemptionError>;
/// 获取待处理的赎回请求
fn get_pending_redemptions(&self) -> Vec<RedemptionRequest>;
}
/// ACC-Redemption标准实现
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RedemptionToken {
state: RedemptionState,
}
impl RedemptionToken {
/// 创建新的赎回管理器
pub fn new() -> Self {
Self {
state: RedemptionState {
redemptions: HashMap::new(),
asset_redemptions: HashMap::new(),
redeemer_redemptions: HashMap::new(),
},
}
}
/// 获取状态的可变引用
pub fn state_mut(&mut self) -> &mut RedemptionState {
&mut self.state
}
/// 获取状态的不可变引用
pub fn state(&self) -> &RedemptionState {
&self.state
}
/// 验证赎回请求
fn validate_request(&self, request: &RedemptionRequest) -> Result<(), RedemptionError> {
// 检查赎回金额
if request.amount == 0 {
return Err(RedemptionError::InsufficientAmount);
}
// 检查赎回价格
if request.redemption_price == 0 {
return Err(RedemptionError::InsufficientAmount);
}
Ok(())
}
}
impl Default for RedemptionToken {
fn default() -> Self {
Self::new()
}
}
impl ACCRedemption for RedemptionToken {
fn submit_redemption(&mut self, mut request: RedemptionRequest) -> Result<(), RedemptionError> {
// 检查赎回请求是否已存在
if self.state.redemptions.contains_key(&request.redemption_id) {
return Err(RedemptionError::RequestAlreadyExists);
}
// 验证赎回请求
self.validate_request(&request)?;
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
request.requested_at = now;
request.status = RedemptionStatus::Pending;
// 计算提前赎回费用
if request.redemption_type == RedemptionType::Early {
if let Some(fee_rate) = request.early_redemption_fee {
let fee = request.amount * fee_rate as u128 / 10000;
request.actual_fee = Some(fee);
}
}
let redemption_id = request.redemption_id.clone();
let asset_id = request.asset_id.clone();
let redeemer = request.redeemer.clone();
// 保存赎回请求
self.state
.redemptions
.insert(redemption_id.clone(), request);
// 更新资产赎回历史
self.state
.asset_redemptions
.entry(asset_id)
.or_insert_with(Vec::new)
.push(redemption_id.clone());
// 更新赎回人赎回列表
self.state
.redeemer_redemptions
.entry(redeemer)
.or_insert_with(Vec::new)
.push(redemption_id);
Ok(())
}
fn get_redemption(&self, redemption_id: &str) -> Result<RedemptionRequest, RedemptionError> {
self.state
.redemptions
.get(redemption_id)
.cloned()
.ok_or(RedemptionError::RequestNotFound)
}
fn get_asset_redemptions(&self, asset_id: &str) -> Vec<RedemptionRequest> {
self.state
.asset_redemptions
.get(asset_id)
.map(|redemption_ids| {
redemption_ids
.iter()
.filter_map(|id| self.state.redemptions.get(id).cloned())
.collect()
})
.unwrap_or_default()
}
fn approve_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
if request.status != RedemptionStatus::Pending {
return Err(RedemptionError::AlreadyCompleted);
}
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
request.status = RedemptionStatus::Approved;
request.approved_at = Some(now);
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn reject_redemption(
&mut self,
redemption_id: &str,
reason: String,
) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
if request.status != RedemptionStatus::Pending {
return Err(RedemptionError::AlreadyCompleted);
}
request.status = RedemptionStatus::Rejected;
request.notes.push(format!("Rejected: {}", reason));
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn process_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
if request.status != RedemptionStatus::Approved {
return Err(RedemptionError::Unauthorized);
}
request.status = RedemptionStatus::Processing;
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn complete_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
if request.status != RedemptionStatus::Processing {
return Err(RedemptionError::Unauthorized);
}
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
request.status = RedemptionStatus::Completed;
request.completed_at = Some(now);
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn cancel_redemption(&mut self, redemption_id: &str) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
if request.status == RedemptionStatus::Completed {
return Err(RedemptionError::AlreadyCompleted);
}
if request.status == RedemptionStatus::Cancelled {
return Err(RedemptionError::AlreadyCancelled);
}
request.status = RedemptionStatus::Cancelled;
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn calculate_redemption_fee(&self, redemption_id: &str) -> Result<u128, RedemptionError> {
let request = self.get_redemption(redemption_id)?;
if let Some(fee) = request.actual_fee {
Ok(fee)
} else {
Ok(0)
}
}
fn update_status(
&mut self,
redemption_id: &str,
status: RedemptionStatus,
) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
request.status = status;
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn get_redeemer_redemptions(&self, redeemer: &str) -> Vec<RedemptionRequest> {
self.state
.redeemer_redemptions
.get(redeemer)
.map(|redemption_ids| {
redemption_ids
.iter()
.filter_map(|id| self.state.redemptions.get(id).cloned())
.collect()
})
.unwrap_or_default()
}
fn add_note(&mut self, redemption_id: &str, note: String) -> Result<(), RedemptionError> {
let mut request = self.get_redemption(redemption_id)?;
request.notes.push(note);
self.state
.redemptions
.insert(redemption_id.to_string(), request);
Ok(())
}
fn get_pending_redemptions(&self) -> Vec<RedemptionRequest> {
self.state
.redemptions
.values()
.filter(|request| request.status == RedemptionStatus::Pending)
.cloned()
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_request() -> RedemptionRequest {
RedemptionRequest {
redemption_id: "RED-001".to_string(),
asset_id: "RWA-001".to_string(),
redeemer: "alice".to_string(),
redemption_type: RedemptionType::Full,
amount: 1000000,
redemption_price: 1000000_00,
status: RedemptionStatus::Pending,
requested_at: 0,
approved_at: None,
completed_at: None,
expected_completion: 1234567890 + 86400 * 7,
early_redemption_fee: None,
actual_fee: None,
notes: Vec::new(),
}
}
#[test]
fn test_submit_redemption() {
let mut redemption = RedemptionToken::new();
let request = create_test_request();
assert!(redemption.submit_redemption(request).is_ok());
}
#[test]
fn test_approve_redemption() {
let mut redemption = RedemptionToken::new();
let request = create_test_request();
redemption.submit_redemption(request).unwrap();
assert!(redemption.approve_redemption("RED-001").is_ok());
assert_eq!(
redemption.get_redemption("RED-001").unwrap().status,
RedemptionStatus::Approved
);
}
#[test]
fn test_complete_redemption() {
let mut redemption = RedemptionToken::new();
let request = create_test_request();
redemption.submit_redemption(request).unwrap();
redemption.approve_redemption("RED-001").unwrap();
redemption.process_redemption("RED-001").unwrap();
assert!(redemption.complete_redemption("RED-001").is_ok());
assert_eq!(
redemption.get_redemption("RED-001").unwrap().status,
RedemptionStatus::Completed
);
}
#[test]
fn test_early_redemption_fee() {
let mut redemption = RedemptionToken::new();
let mut request = create_test_request();
request.redemption_type = RedemptionType::Early;
request.early_redemption_fee = Some(100); // 1%
redemption.submit_redemption(request).unwrap();
let fee = redemption.calculate_redemption_fee("RED-001").unwrap();
assert_eq!(fee, 10000); // 1% of 1000000
}
#[test]
fn test_cancel_redemption() {
let mut redemption = RedemptionToken::new();
let request = create_test_request();
redemption.submit_redemption(request).unwrap();
assert!(redemption.cancel_redemption("RED-001").is_ok());
assert_eq!(
redemption.get_redemption("RED-001").unwrap().status,
RedemptionStatus::Cancelled
);
}
}