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

330 lines
9.5 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-Valuation: 资产估值协议Valuation Protocol
//
// NAC原生的资产估值标准用于资产价值评估和管理
// 100% NAC原生协议不是任何现有标准的实现
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// 估值方法
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ValuationMethod {
/// 市场法
MarketApproach,
/// 收益法
IncomeApproach,
/// 成本法
CostApproach,
/// 其他
Other(String),
}
/// 估值记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValuationRecord {
/// 估值ID
pub valuation_id: String,
/// 资产ID
pub asset_id: String,
/// 估值方法
pub method: ValuationMethod,
/// 估值金额USD以分为单位
pub value: u128,
/// 估值师地址
pub appraiser: String,
/// 估值时间
pub timestamp: u64,
/// 有效期(秒)
pub validity_period: u64,
/// 备注
pub notes: Vec<String>,
}
/// 估值错误类型
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ValuationError {
/// 估值记录不存在
RecordNotFound,
/// 估值记录已存在
RecordAlreadyExists,
/// 估值已过期
ValuationExpired,
/// 无效的估值金额
InvalidValue,
/// 未授权操作
Unauthorized,
}
/// 估值状态
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValuationState {
/// 估值记录映射 (valuation_id -> ValuationRecord)
pub valuations: HashMap<String, ValuationRecord>,
/// 资产估值历史 (asset_id -> [valuation_ids])
pub asset_valuations: HashMap<String, Vec<String>>,
}
/// ACC-Valuation接口
pub trait ACCValuation {
/// 添加估值记录
fn add_valuation(&mut self, record: ValuationRecord) -> Result<(), ValuationError>;
/// 获取估值记录
fn get_valuation(&self, valuation_id: &str) -> Result<ValuationRecord, ValuationError>;
/// 获取资产的最新估值
fn get_latest_valuation(&self, asset_id: &str) -> Result<ValuationRecord, ValuationError>;
/// 获取资产的估值历史
fn get_valuation_history(&self, asset_id: &str) -> Vec<ValuationRecord>;
/// 检查估值是否有效
fn is_valuation_valid(&self, valuation_id: &str) -> bool;
/// 计算平均估值
fn calculate_average_valuation(&self, asset_id: &str, period: u64) -> Option<u128>;
/// 更新估值备注
fn add_note(&mut self, valuation_id: &str, note: String) -> Result<(), ValuationError>;
}
/// ACC-Valuation标准实现
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValuationToken {
state: ValuationState,
}
impl ValuationToken {
/// 创建新的估值管理器
pub fn new() -> Self {
Self {
state: ValuationState {
valuations: HashMap::new(),
asset_valuations: HashMap::new(),
},
}
}
/// 获取状态的可变引用
pub fn state_mut(&mut self) -> &mut ValuationState {
&mut self.state
}
/// 获取状态的不可变引用
pub fn state(&self) -> &ValuationState {
&self.state
}
}
impl Default for ValuationToken {
fn default() -> Self {
Self::new()
}
}
impl ACCValuation for ValuationToken {
fn add_valuation(&mut self, mut record: ValuationRecord) -> Result<(), ValuationError> {
if self.state.valuations.contains_key(&record.valuation_id) {
return Err(ValuationError::RecordAlreadyExists);
}
if record.value == 0 {
return Err(ValuationError::InvalidValue);
}
// 如果timestamp为0使用当前时间
if record.timestamp == 0 {
record.timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
}
let valuation_id = record.valuation_id.clone();
let asset_id = record.asset_id.clone();
self.state
.valuations
.insert(valuation_id.clone(), record);
self.state
.asset_valuations
.entry(asset_id)
.or_insert_with(Vec::new)
.push(valuation_id);
Ok(())
}
fn get_valuation(&self, valuation_id: &str) -> Result<ValuationRecord, ValuationError> {
self.state
.valuations
.get(valuation_id)
.cloned()
.ok_or(ValuationError::RecordNotFound)
}
fn get_latest_valuation(&self, asset_id: &str) -> Result<ValuationRecord, ValuationError> {
let valuation_ids = self
.state
.asset_valuations
.get(asset_id)
.ok_or(ValuationError::RecordNotFound)?;
if valuation_ids.is_empty() {
return Err(ValuationError::RecordNotFound);
}
// 获取所有估值记录并按时间排序
let mut valuations: Vec<ValuationRecord> = valuation_ids
.iter()
.filter_map(|id| self.state.valuations.get(id).cloned())
.collect();
valuations.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
valuations
.into_iter()
.next()
.ok_or(ValuationError::RecordNotFound)
}
fn get_valuation_history(&self, asset_id: &str) -> Vec<ValuationRecord> {
self.state
.asset_valuations
.get(asset_id)
.map(|valuation_ids| {
let mut valuations: Vec<ValuationRecord> = valuation_ids
.iter()
.filter_map(|id| self.state.valuations.get(id).cloned())
.collect();
valuations.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
valuations
})
.unwrap_or_default()
}
fn is_valuation_valid(&self, valuation_id: &str) -> bool {
if let Ok(record) = self.get_valuation(valuation_id) {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
now <= record.timestamp + record.validity_period
} else {
false
}
}
fn calculate_average_valuation(&self, asset_id: &str, period: u64) -> Option<u128> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let valuations = self.get_valuation_history(asset_id);
let recent_valuations: Vec<&ValuationRecord> = valuations
.iter()
.filter(|v| now - v.timestamp <= period)
.collect();
if recent_valuations.is_empty() {
return None;
}
let sum: u128 = recent_valuations.iter().map(|v| v.value).sum();
Some(sum / recent_valuations.len() as u128)
}
fn add_note(&mut self, valuation_id: &str, note: String) -> Result<(), ValuationError> {
let mut record = self.get_valuation(valuation_id)?;
record.notes.push(note);
self.state
.valuations
.insert(valuation_id.to_string(), record);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_valuation() -> ValuationRecord {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
ValuationRecord {
valuation_id: "VAL-001".to_string(),
asset_id: "RWA-001".to_string(),
method: ValuationMethod::MarketApproach,
value: 1000000_00,
appraiser: "appraiser1".to_string(),
timestamp: now,
validity_period: 31536000, // 1年
notes: Vec::new(),
}
}
#[test]
fn test_add_valuation() {
let mut valuation = ValuationToken::new();
let record = create_test_valuation();
assert!(valuation.add_valuation(record).is_ok());
}
#[test]
fn test_get_latest_valuation() {
let mut valuation = ValuationToken::new();
let record = create_test_valuation();
valuation.add_valuation(record).unwrap();
assert!(valuation.get_latest_valuation("RWA-001").is_ok());
}
#[test]
fn test_is_valuation_valid() {
let mut valuation = ValuationToken::new();
let record = create_test_valuation();
valuation.add_valuation(record).unwrap();
assert!(valuation.is_valuation_valid("VAL-001"));
}
#[test]
fn test_calculate_average_valuation() {
let mut valuation = ValuationToken::new();
let mut record1 = create_test_valuation();
record1.valuation_id = "VAL-001".to_string();
record1.value = 1000000_00;
valuation.add_valuation(record1).unwrap();
let mut record2 = create_test_valuation();
record2.valuation_id = "VAL-002".to_string();
record2.value = 1200000_00;
valuation.add_valuation(record2).unwrap();
let avg = valuation.calculate_average_valuation("RWA-001", 31536000);
assert!(avg.is_some());
assert_eq!(avg.unwrap(), 1100000_00);
}
#[test]
fn test_add_note() {
let mut valuation = ValuationToken::new();
let record = create_test_valuation();
valuation.add_valuation(record).unwrap();
assert!(valuation
.add_note("VAL-001", "Test note".to_string())
.is_ok());
assert_eq!(
valuation.get_valuation("VAL-001").unwrap().notes.len(),
1
);
}
}