532 lines
15 KiB
Rust
532 lines
15 KiB
Rust
// ACC-RWA: 真实世界资产协议(Real World Asset Protocol)
|
||
//
|
||
// NAC原生的RWA资产标准,专为真实世界资产上链设计
|
||
// 100% NAC原生协议,不是任何现有标准的实现
|
||
|
||
use serde::{Deserialize, Serialize};
|
||
use std::collections::HashMap;
|
||
|
||
/// RWA资产类型
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum RWAAssetType {
|
||
/// 不动产(房地产、土地)
|
||
RealEstate,
|
||
/// 贵金属(黄金、白银、铂金)
|
||
PreciousMetal,
|
||
/// 艺术品(绘画、雕塑、古董)
|
||
Artwork,
|
||
/// 股权(公司股权、基金份额)
|
||
Equity,
|
||
/// 债券(政府债券、企业债券)
|
||
Bond,
|
||
/// 大宗商品(石油、天然气、农产品)
|
||
Commodity,
|
||
/// 知识产权(专利、商标、版权)
|
||
IntellectualProperty,
|
||
/// 收藏品(邮票、钱币、珠宝)
|
||
Collectible,
|
||
/// 其他
|
||
Other(String),
|
||
}
|
||
|
||
/// RWA资产状态
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum RWAAssetStatus {
|
||
/// 待审核
|
||
Pending,
|
||
/// 已激活
|
||
Active,
|
||
/// 已冻结
|
||
Frozen,
|
||
/// 已注销
|
||
Deactivated,
|
||
}
|
||
|
||
/// RWA资产信息
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct RWAAssetInfo {
|
||
/// 资产ID
|
||
pub asset_id: String,
|
||
/// 资产类型
|
||
pub asset_type: RWAAssetType,
|
||
/// 资产名称
|
||
pub name: String,
|
||
/// 资产描述
|
||
pub description: String,
|
||
/// 资产DNA(NAC原生,简化为String)
|
||
pub asset_dna: String,
|
||
/// GNACS分类编码(NAC原生)
|
||
pub gnacs_code: String,
|
||
/// 所有者地址
|
||
pub owner: String,
|
||
/// 估值(USD,以分为单位)
|
||
pub valuation_usd: u128,
|
||
/// 资产状态
|
||
pub status: RWAAssetStatus,
|
||
/// 物理位置
|
||
pub physical_location: Option<String>,
|
||
/// 法律文件哈希列表(简化为String列表)
|
||
pub legal_documents: Vec<String>,
|
||
/// 创建时间(Unix时间戳)
|
||
pub created_at: u64,
|
||
/// 更新时间(Unix时间戳)
|
||
pub updated_at: u64,
|
||
/// 最后审计时间
|
||
pub last_audited_at: Option<u64>,
|
||
}
|
||
|
||
/// RWA资产错误类型
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||
pub enum RWAError {
|
||
/// 资产不存在
|
||
AssetNotFound,
|
||
/// 资产已存在
|
||
AssetAlreadyExists,
|
||
/// 无效的所有者
|
||
InvalidOwner,
|
||
/// 资产已冻结
|
||
AssetFrozen,
|
||
/// 未授权操作
|
||
Unauthorized,
|
||
/// 无效的资产DNA
|
||
InvalidAssetDNA,
|
||
/// 无效的GNACS编码
|
||
InvalidGNACSCode,
|
||
/// 估值过期
|
||
ValuationExpired,
|
||
/// 法律文件缺失
|
||
MissingLegalDocuments,
|
||
}
|
||
|
||
/// RWA资产状态
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct RWAState {
|
||
/// 资产映射 (asset_id -> RWAAssetInfo)
|
||
pub assets: HashMap<String, RWAAssetInfo>,
|
||
/// 所有者资产列表 (owner -> [asset_ids])
|
||
pub owner_assets: HashMap<String, Vec<String>>,
|
||
/// 资产DNA索引 (dna_hash -> asset_id)
|
||
pub dna_index: HashMap<String, String>,
|
||
/// GNACS索引 (gnacs_code -> [asset_ids])
|
||
pub gnacs_index: HashMap<String, Vec<String>>,
|
||
}
|
||
|
||
/// ACC-RWA接口
|
||
pub trait ACCRwa {
|
||
/// 注册RWA资产
|
||
fn register_asset(&mut self, asset_info: RWAAssetInfo) -> Result<(), RWAError>;
|
||
|
||
/// 获取RWA资产信息
|
||
fn get_asset(&self, asset_id: &str) -> Result<RWAAssetInfo, RWAError>;
|
||
|
||
/// 更新资产估值
|
||
fn update_valuation(&mut self, asset_id: &str, new_valuation: u128) -> Result<(), RWAError>;
|
||
|
||
/// 转移资产所有权
|
||
fn transfer_ownership(&mut self, asset_id: &str, new_owner: String) -> Result<(), RWAError>;
|
||
|
||
/// 冻结资产
|
||
fn freeze_asset(&mut self, asset_id: &str) -> Result<(), RWAError>;
|
||
|
||
/// 解冻资产
|
||
fn unfreeze_asset(&mut self, asset_id: &str) -> Result<(), RWAError>;
|
||
|
||
/// 注销资产
|
||
fn deactivate_asset(&mut self, asset_id: &str) -> Result<(), RWAError>;
|
||
|
||
/// 添加法律文件
|
||
fn add_legal_document(&mut self, asset_id: &str, document_hash: String) -> Result<(), RWAError>;
|
||
|
||
/// 获取所有者的资产列表
|
||
fn get_owner_assets(&self, owner: &str) -> Vec<RWAAssetInfo>;
|
||
|
||
/// 按GNACS编码查询资产
|
||
fn get_assets_by_gnacs(&self, gnacs_code: &str) -> Vec<RWAAssetInfo>;
|
||
|
||
/// 按资产类型查询资产
|
||
fn get_assets_by_type(&self, asset_type: RWAAssetType) -> Vec<RWAAssetInfo>;
|
||
|
||
/// 更新审计时间
|
||
fn update_audit_time(&mut self, asset_id: &str) -> Result<(), RWAError>;
|
||
}
|
||
|
||
/// ACC-RWA标准实现
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
pub struct RwaToken {
|
||
state: RWAState,
|
||
}
|
||
|
||
impl RwaToken {
|
||
/// 创建新的RWA资产管理器
|
||
pub fn new() -> Self {
|
||
Self {
|
||
state: RWAState {
|
||
assets: HashMap::new(),
|
||
owner_assets: HashMap::new(),
|
||
dna_index: HashMap::new(),
|
||
gnacs_index: HashMap::new(),
|
||
},
|
||
}
|
||
}
|
||
|
||
/// 获取状态的可变引用
|
||
pub fn state_mut(&mut self) -> &mut RWAState {
|
||
&mut self.state
|
||
}
|
||
|
||
/// 获取状态的不可变引用
|
||
pub fn state(&self) -> &RWAState {
|
||
&self.state
|
||
}
|
||
|
||
/// 生成资产DNA(简化实现)
|
||
fn generate_asset_dna(&self, asset_id: &str) -> String {
|
||
format!("DNA-{}", asset_id)
|
||
}
|
||
|
||
/// 验证资产DNA
|
||
fn validate_asset_dna(&self, dna: &str) -> bool {
|
||
dna.starts_with("DNA-") && dna.len() > 4
|
||
}
|
||
|
||
/// 验证GNACS编码
|
||
fn validate_gnacs_code(&self, code: &str) -> bool {
|
||
// 简化验证:检查格式(应为NAC-XXXX-XXXX格式)
|
||
code.starts_with("NAC-") && code.len() >= 8
|
||
}
|
||
}
|
||
|
||
impl Default for RwaToken {
|
||
fn default() -> Self {
|
||
Self::new()
|
||
}
|
||
}
|
||
|
||
impl ACCRwa for RwaToken {
|
||
fn register_asset(&mut self, mut asset_info: RWAAssetInfo) -> Result<(), RWAError> {
|
||
// 检查资产是否已存在
|
||
if self.state.assets.contains_key(&asset_info.asset_id) {
|
||
return Err(RWAError::AssetAlreadyExists);
|
||
}
|
||
|
||
// 验证GNACS编码
|
||
if !self.validate_gnacs_code(&asset_info.gnacs_code) {
|
||
return Err(RWAError::InvalidGNACSCode);
|
||
}
|
||
|
||
// 生成资产DNA
|
||
if asset_info.asset_dna.is_empty() {
|
||
asset_info.asset_dna = self.generate_asset_dna(&asset_info.asset_id);
|
||
}
|
||
|
||
// 验证资产DNA
|
||
if !self.validate_asset_dna(&asset_info.asset_dna) {
|
||
return Err(RWAError::InvalidAssetDNA);
|
||
}
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset_info.created_at = now;
|
||
asset_info.updated_at = now;
|
||
asset_info.status = RWAAssetStatus::Active;
|
||
|
||
let asset_id = asset_info.asset_id.clone();
|
||
let owner = asset_info.owner.clone();
|
||
let dna = asset_info.asset_dna.clone();
|
||
let gnacs_code = asset_info.gnacs_code.clone();
|
||
|
||
// 保存资产信息
|
||
self.state.assets.insert(asset_id.clone(), asset_info);
|
||
|
||
// 更新所有者资产列表
|
||
self.state
|
||
.owner_assets
|
||
.entry(owner)
|
||
.or_insert_with(Vec::new)
|
||
.push(asset_id.clone());
|
||
|
||
// 更新DNA索引
|
||
self.state.dna_index.insert(dna, asset_id.clone());
|
||
|
||
// 更新GNACS索引
|
||
self.state
|
||
.gnacs_index
|
||
.entry(gnacs_code)
|
||
.or_insert_with(Vec::new)
|
||
.push(asset_id);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn get_asset(&self, asset_id: &str) -> Result<RWAAssetInfo, RWAError> {
|
||
self.state
|
||
.assets
|
||
.get(asset_id)
|
||
.cloned()
|
||
.ok_or(RWAError::AssetNotFound)
|
||
}
|
||
|
||
fn update_valuation(&mut self, asset_id: &str, new_valuation: u128) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
if asset.status == RWAAssetStatus::Frozen {
|
||
return Err(RWAError::AssetFrozen);
|
||
}
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset.valuation_usd = new_valuation;
|
||
asset.updated_at = now;
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn transfer_ownership(&mut self, asset_id: &str, new_owner: String) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
if asset.status == RWAAssetStatus::Frozen {
|
||
return Err(RWAError::AssetFrozen);
|
||
}
|
||
|
||
let old_owner = asset.owner.clone();
|
||
asset.owner = new_owner.clone();
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
asset.updated_at = now;
|
||
|
||
// 更新所有者资产列表
|
||
if let Some(assets) = self.state.owner_assets.get_mut(&old_owner) {
|
||
assets.retain(|id| id != asset_id);
|
||
}
|
||
self.state
|
||
.owner_assets
|
||
.entry(new_owner)
|
||
.or_insert_with(Vec::new)
|
||
.push(asset_id.to_string());
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn freeze_asset(&mut self, asset_id: &str) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset.status = RWAAssetStatus::Frozen;
|
||
asset.updated_at = now;
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn unfreeze_asset(&mut self, asset_id: &str) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset.status = RWAAssetStatus::Active;
|
||
asset.updated_at = now;
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn deactivate_asset(&mut self, asset_id: &str) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset.status = RWAAssetStatus::Deactivated;
|
||
asset.updated_at = now;
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn add_legal_document(&mut self, asset_id: &str, document_hash: String) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset.legal_documents.push(document_hash);
|
||
asset.updated_at = now;
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
|
||
fn get_owner_assets(&self, owner: &str) -> Vec<RWAAssetInfo> {
|
||
self.state
|
||
.owner_assets
|
||
.get(owner)
|
||
.map(|asset_ids| {
|
||
asset_ids
|
||
.iter()
|
||
.filter_map(|id| self.state.assets.get(id).cloned())
|
||
.collect()
|
||
})
|
||
.unwrap_or_default()
|
||
}
|
||
|
||
fn get_assets_by_gnacs(&self, gnacs_code: &str) -> Vec<RWAAssetInfo> {
|
||
self.state
|
||
.gnacs_index
|
||
.get(gnacs_code)
|
||
.map(|asset_ids| {
|
||
asset_ids
|
||
.iter()
|
||
.filter_map(|id| self.state.assets.get(id).cloned())
|
||
.collect()
|
||
})
|
||
.unwrap_or_default()
|
||
}
|
||
|
||
fn get_assets_by_type(&self, asset_type: RWAAssetType) -> Vec<RWAAssetInfo> {
|
||
self.state
|
||
.assets
|
||
.values()
|
||
.filter(|asset| asset.asset_type == asset_type)
|
||
.cloned()
|
||
.collect()
|
||
}
|
||
|
||
fn update_audit_time(&mut self, asset_id: &str) -> Result<(), RWAError> {
|
||
let mut asset = self.get_asset(asset_id)?;
|
||
|
||
let now = std::time::SystemTime::now()
|
||
.duration_since(std::time::UNIX_EPOCH)
|
||
.unwrap()
|
||
.as_secs();
|
||
|
||
asset.last_audited_at = Some(now);
|
||
asset.updated_at = now;
|
||
|
||
self.state.assets.insert(asset_id.to_string(), asset);
|
||
|
||
Ok(())
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
fn create_test_asset() -> RWAAssetInfo {
|
||
RWAAssetInfo {
|
||
asset_id: "RWA-001".to_string(),
|
||
asset_type: RWAAssetType::RealEstate,
|
||
name: "Test Property".to_string(),
|
||
description: "A test real estate asset".to_string(),
|
||
asset_dna: String::new(),
|
||
gnacs_code: "NAC-RE-001".to_string(),
|
||
owner: "alice".to_string(),
|
||
valuation_usd: 1000000_00,
|
||
status: RWAAssetStatus::Pending,
|
||
physical_location: Some("123 Main St".to_string()),
|
||
legal_documents: vec!["doc1".to_string()],
|
||
created_at: 0,
|
||
updated_at: 0,
|
||
last_audited_at: None,
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_register_asset() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
assert!(rwa.register_asset(asset).is_ok());
|
||
}
|
||
|
||
#[test]
|
||
fn test_update_valuation() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
rwa.register_asset(asset).unwrap();
|
||
|
||
assert!(rwa.update_valuation("RWA-001", 1200000_00).is_ok());
|
||
assert_eq!(rwa.get_asset("RWA-001").unwrap().valuation_usd, 1200000_00);
|
||
}
|
||
|
||
#[test]
|
||
fn test_transfer_ownership() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
rwa.register_asset(asset).unwrap();
|
||
|
||
assert!(rwa.transfer_ownership("RWA-001", "bob".to_string()).is_ok());
|
||
assert_eq!(rwa.get_asset("RWA-001").unwrap().owner, "bob");
|
||
}
|
||
|
||
#[test]
|
||
fn test_freeze_unfreeze_asset() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
rwa.register_asset(asset).unwrap();
|
||
|
||
assert!(rwa.freeze_asset("RWA-001").is_ok());
|
||
assert_eq!(rwa.get_asset("RWA-001").unwrap().status, RWAAssetStatus::Frozen);
|
||
|
||
assert!(rwa.unfreeze_asset("RWA-001").is_ok());
|
||
assert_eq!(rwa.get_asset("RWA-001").unwrap().status, RWAAssetStatus::Active);
|
||
}
|
||
|
||
#[test]
|
||
fn test_add_legal_document() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
rwa.register_asset(asset).unwrap();
|
||
|
||
assert!(rwa.add_legal_document("RWA-001", "doc2".to_string()).is_ok());
|
||
assert_eq!(rwa.get_asset("RWA-001").unwrap().legal_documents.len(), 2);
|
||
}
|
||
|
||
#[test]
|
||
fn test_get_owner_assets() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
rwa.register_asset(asset).unwrap();
|
||
|
||
let assets = rwa.get_owner_assets("alice");
|
||
assert_eq!(assets.len(), 1);
|
||
}
|
||
|
||
#[test]
|
||
fn test_get_assets_by_gnacs() {
|
||
let mut rwa = RwaToken::new();
|
||
let asset = create_test_asset();
|
||
rwa.register_asset(asset).unwrap();
|
||
|
||
let assets = rwa.get_assets_by_gnacs("NAC-RE-001");
|
||
assert_eq!(assets.len(), 1);
|
||
}
|
||
}
|