diff --git a/_archive/acc1155_v1_backup.rs b/_archive/acc1155_v1_backup.rs new file mode 100644 index 0000000..90ed525 --- /dev/null +++ b/_archive/acc1155_v1_backup.rs @@ -0,0 +1,254 @@ +//! ACC-1155: 多代币证书协议 +//! +//! UID: nac.acc.ACC1155.v2 +//! +//! ACC-1155是NAC原生的多代币证书协议,用于在单个证书中管理多种代币类型。 +//! 与ERC-1155不同,ACC-1155集成了NAC的核心特性: +//! - GNACS 48位编码 +//! - 代币类型DNA +//! - 主权类型 +//! - 合规掩码 +//! - 批量操作优化 +//! - 混合资产管理(可替代+不可替代) +//! - 托管信息 +//! - 保险信息 +//! - 碎片化支持 + + +use crate::primitives::{Address, Hash, Timestamp}; +use crate::l1_protocol::gnacs::GNACSCode; +use crate::l2_governance::SovereigntyRight; +use serde::{Deserialize, Serialize}; + +/// 代币ID类型 +pub type TokenId = u128; + +/// 代币类型(可替代性) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum TokenType { + /// 可替代代币(Fungible Token,类似ACC-20) + Fungible, + /// 不可替代代币(Non-Fungible Token,类似ACC-721) + NonFungible, + /// 半可替代代币(Semi-Fungible Token,如游戏道具) + SemiFungible, +} + +/// 代币类型DNA +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenTypeDNA { + /// DNA哈希(Blake3哈希) + pub dna_hash: Hash, + /// 代币类型ID + pub token_id: TokenId, + /// GNACS编码 + pub gnacs_code: GNACSCode, + /// 代币类型(可替代性) + pub token_type: TokenType, + /// 主权类型 + pub sovereignty_type: SovereigntyRight, + /// 元数据哈希 + pub metadata_hash: Hash, + /// 生成时间 + pub generated_at: Timestamp, +} + +/// 代币类型元数据 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenTypeMetadata { + /// 代币类型ID + pub token_id: TokenId, + /// 代币名称 + pub name: String, + /// 代币符号 + pub symbol: String, + /// 代币类型 + pub token_type: TokenType, + /// 元数据URI + pub uri: String, + /// 最大供应量(None表示无限制) + pub max_supply: Option, + /// 当前供应量 + pub current_supply: u128, + /// 创建时间 + pub created_at: Timestamp, +} + +/// 批量转移记录 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BatchTransfer { + /// 发送者地址 + pub from: Address, + /// 接收者地址 + pub to: Address, + /// 代币ID列表 + pub token_ids: Vec, + /// 数量列表 + pub amounts: Vec, + /// 转移时间 + pub transferred_at: Timestamp, + /// 宪法收据哈希 + pub constitutional_receipt: Hash, +} + +/// 批量铸造记录 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BatchMint { + /// 接收者地址 + pub to: Address, + /// 代币ID列表 + pub token_ids: Vec, + /// 数量列表 + pub amounts: Vec, + /// 铸造时间 + pub minted_at: Timestamp, + /// 宪法收据哈希 + pub constitutional_receipt: Hash, +} + +/// 批量销毁记录 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BatchBurn { + /// 持有者地址 + pub from: Address, + /// 代币ID列表 + pub token_ids: Vec, + /// 数量列表 + pub amounts: Vec, + /// 销毁时间 + pub burned_at: Timestamp, + /// 宪法收据哈希 + pub constitutional_receipt: Hash, +} + +/// 托管信息(按代币类型) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenCustodyInfo { + /// 代币类型ID + pub token_id: TokenId, + /// 托管方地址 + pub custodian: Address, + /// 托管开始时间 + pub custody_start: Timestamp, + /// 托管状态 + pub is_active: bool, + /// 托管证明哈希 + pub custody_proof: Hash, +} + +/// 保险信息(按代币类型) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenInsuranceInfo { + /// 代币类型ID + pub token_id: TokenId, + /// 保险提供者地址 + pub insurer: Address, + /// 单位保险金额(XTZH) + pub coverage_per_unit_xtzh: u128, + /// 保险开始时间 + pub insurance_start: Timestamp, + /// 保险到期时间 + pub insurance_expiry: Timestamp, + /// 保险单号 + pub policy_number: String, +} + +/// 代币类型估值 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenTypeValuation { + /// 代币类型ID + pub token_id: TokenId, + /// 单位估值金额(XTZH) + pub value_per_unit_xtzh: u128, + /// 估值提供者地址 + pub valuation_provider: Address, + /// 估值时间 + pub valued_at: Timestamp, + /// 估值有效期(秒) + pub validity_period: u64, +} + +/// 授权信息 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ApprovalInfo { + /// 所有者地址 + pub owner: Address, + /// 被授权者地址 + pub operator: Address, + /// 是否授权 + pub approved: bool, + /// 授权时间 + pub approved_at: Timestamp, +} + +/// 代币余额信息 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenBalance { + /// 持有者地址 + pub holder: Address, + /// 代币类型ID + pub token_id: TokenId, + /// 余额 + pub balance: u128, + /// 最后更新时间 + pub last_updated: Timestamp, +} + +/// 混合资产池(同时管理可替代和不可替代代币) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct HybridAssetPool { + /// 证书地址 + pub certificate_address: Address, + /// 可替代代币ID列表 + pub fungible_token_ids: Vec, + /// 不可替代代币ID列表 + pub non_fungible_token_ids: Vec, + /// 半可替代代币ID列表 + pub semi_fungible_token_ids: Vec, + /// 创建时间 + pub created_at: Timestamp, +} + +/// 代币类型配置 +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenTypeConfig { + /// 代币类型ID + pub token_id: TokenId, + /// 是否可铸造 + pub mintable: bool, + /// 是否可销毁 + pub burnable: bool, + /// 是否可暂停 + pub pausable: bool, + /// 是否需要合规检查 + pub compliance_required: bool, + /// 最小转移数量 + pub min_transfer_amount: u128, + /// 创建时间 + pub created_at: Timestamp, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::primitives::SovereigntyType; + + #[test] + fn test_token_type() { + let fungible = TokenType::Fungible; + let non_fungible = TokenType::NonFungible; + let semi_fungible = TokenType::SemiFungible; + + assert_ne!(fungible, non_fungible); + assert_ne!(fungible, semi_fungible); + assert_ne!(non_fungible, semi_fungible); + } + + #[test] + fn test_sovereignty_type() { + let a0 = SovereigntyType::A0; + let c0 = SovereigntyType::C0; + + assert_ne!(a0, c0); + } +} diff --git a/_archive/acc20_v1_backup.rs b/_archive/acc20_v1_backup.rs new file mode 100644 index 0000000..7f3e986 --- /dev/null +++ b/_archive/acc20_v1_backup.rs @@ -0,0 +1,164 @@ +//! ACC协议模块 + +///! # ACC-20: 可替代代币标准 +///! +///! UID: nac.acc.ACC20.v1 +///! +///! ACC-20是NAC的可替代代币标准,完全替代以太坊的ERC-20。 + +#[allow(unused_imports)] +use crate::primitives::{Address, Hash, Timestamp}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +/// ACC-20代币 +/// +/// UID: nac.acc.ACC20.v1 +#[derive(Debug, Clone, Serialize, Deserialize)] +/// ACC20Token +pub struct ACC20Token { + /// 代币名称 + pub name: String, + + /// 代币符号 + pub symbol: String, + + /// 小数位数 + pub decimals: u8, + + /// 总供应量 + pub total_supply: u128, + + /// 合约地址 + pub contract_address: Address, + + /// 余额映射 + pub balances: HashMap, + + /// 授权映射 (owner -> spender -> amount) + pub allowances: HashMap>, + + /// 创建时间 + pub created_at: Timestamp, +} + +impl ACC20Token { + /// 创建新的ACC-20代币 + pub fn new(name: String, symbol: String, decimals: u8, total_supply: u128) -> Self { + Self { + name, + symbol, + decimals, + total_supply, + contract_address: Address::zero(), + balances: HashMap::new(), + allowances: HashMap::new(), + created_at: Timestamp::now(), + } + } + + /// 获取余额 + pub fn balance_of(&self, owner: &Address) -> u128 { + *self.balances.get(owner).unwrap_or(&0) + } + + /// 转账 + pub fn transfer(&mut self, from: &Address, to: &Address, amount: u128) -> Result<(), String> { + let from_balance = self.balance_of(from); + if from_balance < amount { + return Err("Insufficient balance".to_string()); + } + + self.balances.insert(*from, from_balance - amount); + let to_balance = self.balance_of(to); + self.balances.insert(*to, to_balance + amount); + + Ok(()) + } + + /// 授权 + pub fn approve(&mut self, owner: &Address, spender: &Address, amount: u128) { + self.allowances + .entry(*owner) + .or_insert_with(HashMap::new) + .insert(*spender, amount); + } + + /// 获取授权额度 + pub fn allowance(&self, owner: &Address, spender: &Address) -> u128 { + self.allowances + .get(owner) + .and_then(|spenders| spenders.get(spender)) + .copied() + .unwrap_or(0) + } + + /// 从授权额度转账 + pub fn transfer_from( + &mut self, + spender: &Address, + from: &Address, + to: &Address, + amount: u128, + ) -> Result<(), String> { + let allowed = self.allowance(from, spender); + if allowed < amount { + return Err("Insufficient allowance".to_string()); + } + + self.transfer(from, to, amount)?; + self.approve(from, spender, allowed - amount); + + Ok(()) + } + + /// 铸造代币 + pub fn mint(&mut self, to: &Address, amount: u128) -> Result<(), String> { + let balance = self.balance_of(to); + self.balances.insert(*to, balance + amount); + self.total_supply += amount; + Ok(()) + } + + /// 销毁代币 + pub fn burn(&mut self, from: &Address, amount: u128) -> Result<(), String> { + let balance = self.balance_of(from); + if balance < amount { + return Err("Insufficient balance to burn".to_string()); + } + + self.balances.insert(*from, balance - amount); + self.total_supply -= amount; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + + + #[test] + fn test_acc20_creation() { + let token = ACC20Token::new("Test Token".to_string(), "TEST".to_string(), 18, 1_000_000); + assert_eq!(token.name, "Test Token"); + assert_eq!(token.symbol, "TEST"); + assert_eq!(token.decimals, 18); + assert_eq!(token.total_supply, 1_000_000); + } + + #[test] + fn test_acc20_transfer() { + let mut token = ACC20Token::new("Test".to_string(), "TST".to_string(), 18, 1_000_000); + let addr1 = Address::new([1u8; 32]); + let addr2 = Address::new([2u8; 32]); + + token.mint(&addr1, 1000).unwrap(); + assert_eq!(token.balance_of(&addr1), 1000); + + token.transfer(&addr1, &addr2, 500).unwrap(); + assert_eq!(token.balance_of(&addr1), 500); + assert_eq!(token.balance_of(&addr2), 500); + } +} diff --git a/nac-udm/src/l1_protocol/acc/acc1155.rs b/nac-udm/src/l1_protocol/acc/acc1155.rs index 90ed525..c90df2e 100644 --- a/nac-udm/src/l1_protocol/acc/acc1155.rs +++ b/nac-udm/src/l1_protocol/acc/acc1155.rs @@ -1,254 +1,700 @@ -//! ACC-1155: 多代币证书协议 -//! -//! UID: nac.acc.ACC1155.v2 -//! -//! ACC-1155是NAC原生的多代币证书协议,用于在单个证书中管理多种代币类型。 -//! 与ERC-1155不同,ACC-1155集成了NAC的核心特性: -//! - GNACS 48位编码 -//! - 代币类型DNA -//! - 主权类型 -//! - 合规掩码 -//! - 批量操作优化 -//! - 混合资产管理(可替代+不可替代) -//! - 托管信息 -//! - 保险信息 -//! - 碎片化支持 +//! ACC-1155: NAC 原生多代币标准(Fungible + NFT + SemiFungible 混合) +//! 协议 UID: nac.acc.ACC1155.v1 +//! 完全基于 NAC 原生类型系统 - -use crate::primitives::{Address, Hash, Timestamp}; -use crate::l1_protocol::gnacs::GNACSCode; -use crate::l2_governance::SovereigntyRight; +use std::collections::HashMap; use serde::{Deserialize, Serialize}; +use crate::primitives::{Address, Hash, Timestamp}; -/// 代币ID类型 -pub type TokenId = u128; +pub type TokenId = [u8; 32]; -/// 代币类型(可替代性) #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum TokenType { - /// 可替代代币(Fungible Token,类似ACC-20) Fungible, - /// 不可替代代币(Non-Fungible Token,类似ACC-721) NonFungible, - /// 半可替代代币(Semi-Fungible Token,如游戏道具) SemiFungible, } -/// 代币类型DNA -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenTypeDNA { - /// DNA哈希(Blake3哈希) - pub dna_hash: Hash, - /// 代币类型ID - pub token_id: TokenId, - /// GNACS编码 - pub gnacs_code: GNACSCode, - /// 代币类型(可替代性) - pub token_type: TokenType, - /// 主权类型 - pub sovereignty_type: SovereigntyRight, - /// 元数据哈希 - pub metadata_hash: Hash, - /// 生成时间 - pub generated_at: Timestamp, +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum ACC1155Error { + TokenNotFound(TokenId), + InsufficientBalance { holder: Address, token_id: TokenId, required: u128, available: u128 }, + InvalidConstitutionalReceipt, + AccountFrozen(Address), + TransferHalted, + ZeroAmount, + Unauthorized(Address), + ArrayLengthMismatch, + TokenAlreadyExists(TokenId), + SupplyCapExceeded { token_id: TokenId, cap: u128, current: u128, requested: u128 }, + OperatorNotApproved { owner: Address, operator: Address }, +} + +impl std::fmt::Display for ACC1155Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TokenNotFound(id) => write!(f, "代币类型不存在: {:?}", id), + Self::InsufficientBalance { holder, token_id, required, available } => + write!(f, "余额不足: 持有者 {} 代币 {:?} 需要 {} 实际 {}", holder.to_hex(), token_id, required, available), + Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"), + Self::AccountFrozen(a) => write!(f, "账户已冻结: {}", a.to_hex()), + Self::TransferHalted => write!(f, "转账已暂停"), + Self::ZeroAmount => write!(f, "金额不能为零"), + Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()), + Self::ArrayLengthMismatch => write!(f, "数组长度不匹配"), + Self::TokenAlreadyExists(id) => write!(f, "代币类型已存在: {:?}", id), + Self::SupplyCapExceeded { token_id, cap, current, requested } => + write!(f, "超出供应上限: 代币 {:?} 上限 {} 当前 {} 请求 {}", token_id, cap, current, requested), + Self::OperatorNotApproved { owner, operator } => + write!(f, "操作者未授权: 所有者 {} 操作者 {}", owner.to_hex(), operator.to_hex()), + } + } } -/// 代币类型元数据 #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenTypeMetadata { - /// 代币类型ID +pub struct TokenTypeInfo { pub token_id: TokenId, - /// 代币名称 + pub token_type: TokenType, pub name: String, - /// 代币符号 pub symbol: String, - /// 代币类型 - pub token_type: TokenType, - /// 元数据URI pub uri: String, - /// 最大供应量(None表示无限制) - pub max_supply: Option, - /// 当前供应量 - pub current_supply: u128, - /// 创建时间 + pub total_supply: u128, + pub supply_cap: Option, + pub gnacs_code: String, pub created_at: Timestamp, + pub is_paused: bool, } -/// 批量转移记录 #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BatchTransfer { - /// 发送者地址 - pub from: Address, - /// 接收者地址 - pub to: Address, - /// 代币ID列表 - pub token_ids: Vec, - /// 数量列表 - pub amounts: Vec, - /// 转移时间 - pub transferred_at: Timestamp, - /// 宪法收据哈希 - pub constitutional_receipt: Hash, +pub enum ACC1155Event { + TransferSingle { + operator: Address, + from: Address, + to: Address, + token_id: TokenId, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + TransferBatch { + operator: Address, + from: Address, + to: Address, + token_ids: Vec, + amounts: Vec, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + MintSingle { + to: Address, + token_id: TokenId, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + MintBatch { + to: Address, + token_ids: Vec, + amounts: Vec, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + BurnSingle { + from: Address, + token_id: TokenId, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + BurnBatch { + from: Address, + token_ids: Vec, + amounts: Vec, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + OperatorApproval { + owner: Address, + operator: Address, + approved: bool, + timestamp: Timestamp, + }, + TokenTypeRegistered { + token_id: TokenId, + token_type: TokenType, + name: String, + timestamp: Timestamp, + }, } -/// 批量铸造记录 +/// ACC-1155 多代币协议主结构体 #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BatchMint { - /// 接收者地址 - pub to: Address, - /// 代币ID列表 - pub token_ids: Vec, - /// 数量列表 - pub amounts: Vec, - /// 铸造时间 - pub minted_at: Timestamp, - /// 宪法收据哈希 - pub constitutional_receipt: Hash, -} +pub struct ACC1155 { + pub protocol_uid: String, + pub lens_protocol_vector: String, -/// 批量销毁记录 -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BatchBurn { - /// 持有者地址 - pub from: Address, - /// 代币ID列表 - pub token_ids: Vec, - /// 数量列表 - pub amounts: Vec, - /// 销毁时间 - pub burned_at: Timestamp, - /// 宪法收据哈希 - pub constitutional_receipt: Hash, -} + /// 代币类型注册表 + pub token_types: HashMap, -/// 托管信息(按代币类型) -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenCustodyInfo { - /// 代币类型ID - pub token_id: TokenId, - /// 托管方地址 - pub custodian: Address, - /// 托管开始时间 - pub custody_start: Timestamp, - /// 托管状态 - pub is_active: bool, - /// 托管证明哈希 - pub custody_proof: Hash, -} + /// 持仓: holdings[token_id][holder] = amount + pub holdings: HashMap>, -/// 保险信息(按代币类型) -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenInsuranceInfo { - /// 代币类型ID - pub token_id: TokenId, - /// 保险提供者地址 - pub insurer: Address, - /// 单位保险金额(XTZH) - pub coverage_per_unit_xtzh: u128, - /// 保险开始时间 - pub insurance_start: Timestamp, - /// 保险到期时间 - pub insurance_expiry: Timestamp, - /// 保险单号 - pub policy_number: String, -} + /// 操作者授权: operator_approvals[owner][operator] = approved + pub operator_approvals: HashMap>, -/// 代币类型估值 -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenTypeValuation { - /// 代币类型ID - pub token_id: TokenId, - /// 单位估值金额(XTZH) - pub value_per_unit_xtzh: u128, - /// 估值提供者地址 - pub valuation_provider: Address, - /// 估值时间 - pub valued_at: Timestamp, - /// 估值有效期(秒) - pub validity_period: u64, -} + /// 冻结账户 + pub frozen_accounts: HashMap, -/// 授权信息 -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ApprovalInfo { - /// 所有者地址 + /// 全局暂停 + pub transfer_halted: bool, + + /// 所有者 pub owner: Address, - /// 被授权者地址 - pub operator: Address, - /// 是否授权 - pub approved: bool, - /// 授权时间 - pub approved_at: Timestamp, -} -/// 代币余额信息 -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenBalance { - /// 持有者地址 - pub holder: Address, - /// 代币类型ID - pub token_id: TokenId, - /// 余额 - pub balance: u128, - /// 最后更新时间 - pub last_updated: Timestamp, -} + /// 待广播事件 + pub pending_events: Vec, -/// 混合资产池(同时管理可替代和不可替代代币) -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct HybridAssetPool { - /// 证书地址 - pub certificate_address: Address, - /// 可替代代币ID列表 - pub fungible_token_ids: Vec, - /// 不可替代代币ID列表 - pub non_fungible_token_ids: Vec, - /// 半可替代代币ID列表 - pub semi_fungible_token_ids: Vec, - /// 创建时间 pub created_at: Timestamp, + pub updated_at: Timestamp, } -/// 代币类型配置 -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TokenTypeConfig { - /// 代币类型ID - pub token_id: TokenId, - /// 是否可铸造 - pub mintable: bool, - /// 是否可销毁 - pub burnable: bool, - /// 是否可暂停 - pub pausable: bool, - /// 是否需要合规检查 - pub compliance_required: bool, - /// 最小转移数量 - pub min_transfer_amount: u128, - /// 创建时间 - pub created_at: Timestamp, +impl ACC1155 { + pub fn new(owner: Address, timestamp: Timestamp) -> Self { + Self { + protocol_uid: "nac.acc.ACC1155.v1".to_string(), + lens_protocol_vector: "ACC-1155".to_string(), + token_types: HashMap::new(), + holdings: HashMap::new(), + operator_approvals: HashMap::new(), + frozen_accounts: HashMap::new(), + transfer_halted: false, + owner, + pending_events: Vec::new(), + created_at: timestamp.clone(), + updated_at: timestamp, + } + } + + // ======================== + // 代币类型注册 + // ======================== + + /// 注册新代币类型 + pub fn register_token_type( + &mut self, + caller: &Address, + token_id: TokenId, + token_type: TokenType, + name: String, + symbol: String, + uri: String, + supply_cap: Option, + gnacs_code: String, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC1155Error> { + if constitutional_receipt.is_zero() { + return Err(ACC1155Error::InvalidConstitutionalReceipt); + } + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + if self.token_types.contains_key(&token_id) { + return Err(ACC1155Error::TokenAlreadyExists(token_id)); + } + + let info = TokenTypeInfo { + token_id, + token_type, + name: name.clone(), + symbol, + uri, + total_supply: 0, + supply_cap, + gnacs_code, + created_at: timestamp.clone(), + is_paused: false, + }; + + self.token_types.insert(token_id, info); + self.pending_events.push(ACC1155Event::TokenTypeRegistered { + token_id, + token_type, + name, + timestamp, + }); + Ok(()) + } + + // ======================== + // 查询方法 + // ======================== + + /// 查询单个代币余额 + pub fn balance_of(&self, holder: &Address, token_id: &TokenId) -> u128 { + self.holdings + .get(token_id) + .and_then(|m| m.get(holder)) + .copied() + .unwrap_or(0) + } + + /// 批量查询余额 + pub fn balance_of_batch( + &self, + holders: &[Address], + token_ids: &[TokenId], + ) -> Result, ACC1155Error> { + if holders.len() != token_ids.len() { + return Err(ACC1155Error::ArrayLengthMismatch); + } + Ok(holders.iter().zip(token_ids.iter()) + .map(|(h, t)| self.balance_of(h, t)) + .collect()) + } + + /// 检查操作者授权 + pub fn is_approved_for_all(&self, owner: &Address, operator: &Address) -> bool { + self.operator_approvals + .get(owner) + .and_then(|m| m.get(operator)) + .copied() + .unwrap_or(false) + } + + /// 检查账户是否冻结 + pub fn is_frozen(&self, account: &Address) -> bool { + self.frozen_accounts.contains_key(account) + } + + // ======================== + // 转账方法 + // ======================== + + /// 单代币转账 + pub fn safe_transfer_from( + &mut self, + operator: &Address, + from: &Address, + to: &Address, + token_id: TokenId, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC1155Error> { + if constitutional_receipt.is_zero() { + return Err(ACC1155Error::InvalidConstitutionalReceipt); + } + if amount == 0 { + return Err(ACC1155Error::ZeroAmount); + } + if self.transfer_halted { + return Err(ACC1155Error::TransferHalted); + } + if self.is_frozen(from) { + return Err(ACC1155Error::AccountFrozen(from.clone())); + } + if self.is_frozen(to) { + return Err(ACC1155Error::AccountFrozen(to.clone())); + } + + // 检查操作者权限 + if operator != from && !self.is_approved_for_all(from, operator) { + return Err(ACC1155Error::OperatorNotApproved { + owner: from.clone(), + operator: operator.clone(), + }); + } + + if !self.token_types.contains_key(&token_id) { + return Err(ACC1155Error::TokenNotFound(token_id)); + } + + let from_balance = self.balance_of(from, &token_id); + if from_balance < amount { + return Err(ACC1155Error::InsufficientBalance { + holder: from.clone(), + token_id, + required: amount, + available: from_balance, + }); + } + + *self.holdings.get_mut(&token_id).unwrap().get_mut(from).unwrap() -= amount; + *self.holdings.entry(token_id).or_default().entry(to.clone()).or_insert(0) += amount; + + self.pending_events.push(ACC1155Event::TransferSingle { + operator: operator.clone(), + from: from.clone(), + to: to.clone(), + token_id, + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); + Ok(()) + } + + /// 批量代币转账 + pub fn safe_batch_transfer_from( + &mut self, + operator: &Address, + from: &Address, + to: &Address, + token_ids: Vec, + amounts: Vec, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC1155Error> { + if constitutional_receipt.is_zero() { + return Err(ACC1155Error::InvalidConstitutionalReceipt); + } + if token_ids.len() != amounts.len() { + return Err(ACC1155Error::ArrayLengthMismatch); + } + if self.transfer_halted { + return Err(ACC1155Error::TransferHalted); + } + if self.is_frozen(from) { + return Err(ACC1155Error::AccountFrozen(from.clone())); + } + if self.is_frozen(to) { + return Err(ACC1155Error::AccountFrozen(to.clone())); + } + if operator != from && !self.is_approved_for_all(from, operator) { + return Err(ACC1155Error::OperatorNotApproved { + owner: from.clone(), + operator: operator.clone(), + }); + } + + // 预检查所有余额 + for (token_id, &amount) in token_ids.iter().zip(amounts.iter()) { + if !self.token_types.contains_key(token_id) { + return Err(ACC1155Error::TokenNotFound(*token_id)); + } + let bal = self.balance_of(from, token_id); + if bal < amount { + return Err(ACC1155Error::InsufficientBalance { + holder: from.clone(), + token_id: *token_id, + required: amount, + available: bal, + }); + } + } + + // 执行转账 + for (token_id, &amount) in token_ids.iter().zip(amounts.iter()) { + if amount > 0 { + *self.holdings.get_mut(token_id).unwrap().get_mut(from).unwrap() -= amount; + *self.holdings.entry(*token_id).or_default().entry(to.clone()).or_insert(0) += amount; + } + } + + self.pending_events.push(ACC1155Event::TransferBatch { + operator: operator.clone(), + from: from.clone(), + to: to.clone(), + token_ids, + amounts, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); + Ok(()) + } + + // ======================== + // 铸造/销毁 + // ======================== + + /// 铸造单个代币 + pub fn mint( + &mut self, + caller: &Address, + to: &Address, + token_id: TokenId, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC1155Error> { + if constitutional_receipt.is_zero() { + return Err(ACC1155Error::InvalidConstitutionalReceipt); + } + if amount == 0 { + return Err(ACC1155Error::ZeroAmount); + } + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + + let token_info = self.token_types.get_mut(&token_id) + .ok_or(ACC1155Error::TokenNotFound(token_id))?; + + if let Some(cap) = token_info.supply_cap { + if token_info.total_supply.saturating_add(amount) > cap { + return Err(ACC1155Error::SupplyCapExceeded { + token_id, + cap, + current: token_info.total_supply, + requested: amount, + }); + } + } + + token_info.total_supply = token_info.total_supply.saturating_add(amount); + *self.holdings.entry(token_id).or_default().entry(to.clone()).or_insert(0) += amount; + + self.pending_events.push(ACC1155Event::MintSingle { + to: to.clone(), + token_id, + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); + Ok(()) + } + + /// 批量铸造 + pub fn mint_batch( + &mut self, + caller: &Address, + to: &Address, + token_ids: Vec, + amounts: Vec, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC1155Error> { + if constitutional_receipt.is_zero() { + return Err(ACC1155Error::InvalidConstitutionalReceipt); + } + if token_ids.len() != amounts.len() { + return Err(ACC1155Error::ArrayLengthMismatch); + } + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + + // 预检查 + for (token_id, &amount) in token_ids.iter().zip(amounts.iter()) { + let info = self.token_types.get(token_id) + .ok_or(ACC1155Error::TokenNotFound(*token_id))?; + if let Some(cap) = info.supply_cap { + if info.total_supply.saturating_add(amount) > cap { + return Err(ACC1155Error::SupplyCapExceeded { + token_id: *token_id, + cap, + current: info.total_supply, + requested: amount, + }); + } + } + } + + // 执行铸造 + for (token_id, &amount) in token_ids.iter().zip(amounts.iter()) { + if amount > 0 { + self.token_types.get_mut(token_id).unwrap().total_supply = + self.token_types[token_id].total_supply.saturating_add(amount); + *self.holdings.entry(*token_id).or_default().entry(to.clone()).or_insert(0) += amount; + } + } + + self.pending_events.push(ACC1155Event::MintBatch { + to: to.clone(), + token_ids, + amounts, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); + Ok(()) + } + + /// 销毁单个代币 + pub fn burn( + &mut self, + from: &Address, + token_id: TokenId, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC1155Error> { + if constitutional_receipt.is_zero() { + return Err(ACC1155Error::InvalidConstitutionalReceipt); + } + if amount == 0 { + return Err(ACC1155Error::ZeroAmount); + } + + let balance = self.balance_of(from, &token_id); + if balance < amount { + return Err(ACC1155Error::InsufficientBalance { + holder: from.clone(), + token_id, + required: amount, + available: balance, + }); + } + + *self.holdings.get_mut(&token_id).unwrap().get_mut(from).unwrap() -= amount; + if let Some(info) = self.token_types.get_mut(&token_id) { + info.total_supply = info.total_supply.saturating_sub(amount); + } + + self.pending_events.push(ACC1155Event::BurnSingle { + from: from.clone(), + token_id, + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); + Ok(()) + } + + // ======================== + // 操作者授权 + // ======================== + + /// 设置操作者授权 + pub fn set_approval_for_all( + &mut self, + owner: &Address, + operator: &Address, + approved: bool, + timestamp: Timestamp, + ) { + self.operator_approvals + .entry(owner.clone()) + .or_default() + .insert(operator.clone(), approved); + + self.pending_events.push(ACC1155Event::OperatorApproval { + owner: owner.clone(), + operator: operator.clone(), + approved, + timestamp, + }); + } + + // ======================== + // 合规控制 + // ======================== + + /// 冻结账户 + pub fn freeze_account( + &mut self, + caller: &Address, + account: &Address, + reason: String, + ) -> Result<(), ACC1155Error> { + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + self.frozen_accounts.insert(account.clone(), reason); + Ok(()) + } + + /// 解冻账户 + pub fn unfreeze_account( + &mut self, + caller: &Address, + account: &Address, + ) -> Result<(), ACC1155Error> { + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + self.frozen_accounts.remove(account); + Ok(()) + } + + /// 暂停转账 + pub fn halt_transfers( + &mut self, + caller: &Address, + ) -> Result<(), ACC1155Error> { + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + self.transfer_halted = true; + Ok(()) + } + + /// 恢复转账 + pub fn resume_transfers( + &mut self, + caller: &Address, + ) -> Result<(), ACC1155Error> { + if caller != &self.owner { + return Err(ACC1155Error::Unauthorized(caller.clone())); + } + self.transfer_halted = false; + Ok(()) + } + + /// 排空待广播事件 + pub fn drain_pending_events(&mut self) -> Vec { + std::mem::take(&mut self.pending_events) + } } #[cfg(test)] mod tests { use super::*; - use crate::primitives::SovereigntyType; + + fn make_addr(b: u8) -> Address { Address::new([b; 32]) } + fn make_token_id(b: u8) -> TokenId { [b; 32] } + fn make_hash(b: u8) -> Hash { Hash::sha3_384(&[b; 48]) } #[test] - fn test_token_type() { - let fungible = TokenType::Fungible; - let non_fungible = TokenType::NonFungible; - let semi_fungible = TokenType::SemiFungible; + fn test_register_and_mint() { + let owner = make_addr(1); + let ts = Timestamp::now(); + let mut acc = ACC1155::new(owner.clone(), ts.clone()); + let token_id = make_token_id(10); + let receipt = make_hash(9); - assert_ne!(fungible, non_fungible); - assert_ne!(fungible, semi_fungible); - assert_ne!(non_fungible, semi_fungible); + acc.register_token_type( + &owner, token_id, TokenType::Fungible, + "RWA Token".to_string(), "RWA".to_string(), + "ipfs://...".to_string(), Some(1_000_000), "1.1.1.1.1.1".to_string(), + receipt.clone(), ts.clone(), + ).unwrap(); + + acc.mint(&owner, &owner, token_id, 500, receipt, ts).unwrap(); + assert_eq!(acc.balance_of(&owner, &token_id), 500); } #[test] - fn test_sovereignty_type() { - let a0 = SovereigntyType::A0; - let c0 = SovereigntyType::C0; + fn test_batch_transfer() { + let owner = make_addr(1); + let receiver = make_addr(2); + let ts = Timestamp::now(); + let mut acc = ACC1155::new(owner.clone(), ts.clone()); + let t1 = make_token_id(1); + let t2 = make_token_id(2); + let receipt = make_hash(9); - assert_ne!(a0, c0); + for tid in [t1, t2] { + acc.register_token_type( + &owner, tid, TokenType::Fungible, + "T".to_string(), "T".to_string(), "".to_string(), + None, "1.1.1.1.1.1".to_string(), receipt.clone(), ts.clone(), + ).unwrap(); + acc.mint(&owner, &owner, tid, 1000, receipt.clone(), ts.clone()).unwrap(); + } + + acc.safe_batch_transfer_from( + &owner, &owner, &receiver, + vec![t1, t2], vec![300, 400], + receipt, ts, + ).unwrap(); + + assert_eq!(acc.balance_of(&owner, &t1), 700); + assert_eq!(acc.balance_of(&receiver, &t2), 400); } } diff --git a/nac-udm/src/l1_protocol/acc/acc20.rs b/nac-udm/src/l1_protocol/acc/acc20.rs index 7f3e986..5c8ed36 100644 --- a/nac-udm/src/l1_protocol/acc/acc20.rs +++ b/nac-udm/src/l1_protocol/acc/acc20.rs @@ -1,164 +1,664 @@ -//! ACC协议模块 +//! ACC-20: NAC 原生同质化代币标准 +//! 协议 UID: nac.acc.ACC20Token.v2 +//! 完全基于 NAC 原生类型系统,无以太坊模式残留 -///! # ACC-20: 可替代代币标准 -///! -///! UID: nac.acc.ACC20.v1 -///! -///! ACC-20是NAC的可替代代币标准,完全替代以太坊的ERC-20。 - -#[allow(unused_imports)] -use crate::primitives::{Address, Hash, Timestamp}; -use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use serde::{Deserialize, Serialize}; +use crate::primitives::{Address, Hash, Timestamp}; + +// ======================== +// 错误类型 +// ======================== + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum ACC20Error { + InsufficientBalance { holder: Address, required: u128, available: u128 }, + InsufficientAllowance { owner: Address, spender: Address, required: u128, available: u128 }, + InvalidConstitutionalReceipt, + AccountFrozen(Address), + TransferHalted, + ZeroAmount, + Overflow, + Unauthorized(Address), + InvalidAddress, + SupplyCapExceeded { cap: u128, current: u128, requested: u128 }, +} + +impl std::fmt::Display for ACC20Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InsufficientBalance { holder, required, available } => + write!(f, "余额不足: 持有者 {} 需要 {} 实际 {}", holder.to_hex(), required, available), + Self::InsufficientAllowance { owner, spender, required, available } => + write!(f, "授权额度不足: 所有者 {} 授权给 {} 需要 {} 实际 {}", owner.to_hex(), spender.to_hex(), required, available), + Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"), + Self::AccountFrozen(a) => write!(f, "账户已冻结: {}", a.to_hex()), + Self::TransferHalted => write!(f, "转账已暂停"), + Self::ZeroAmount => write!(f, "金额不能为零"), + Self::Overflow => write!(f, "数值溢出"), + Self::Unauthorized(a) => write!(f, "未授权操作: {}", a.to_hex()), + Self::InvalidAddress => write!(f, "无效地址"), + Self::SupplyCapExceeded { cap, current, requested } => + write!(f, "超出供应上限: 上限 {} 当前 {} 请求 {}", cap, current, requested), + } + } +} + +// ======================== +// 协议事件(CSNP 广播) +// ======================== -/// ACC-20代币 -/// -/// UID: nac.acc.ACC20.v1 #[derive(Debug, Clone, Serialize, Deserialize)] -/// ACC20Token +pub enum ACC20Event { + /// 代币转移 + Transfer { + from: Address, + to: Address, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + /// 授权额度变更 + Approval { + owner: Address, + spender: Address, + amount: u128, + timestamp: Timestamp, + }, + /// 铸造 + Mint { + to: Address, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + /// 销毁 + Burn { + from: Address, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + /// 账户冻结 + AccountFrozen { + account: Address, + reason: String, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + /// 账户解冻 + AccountUnfrozen { + account: Address, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + /// 转账暂停 + TransferHalted { + reason: String, + constitutional_receipt: Hash, + timestamp: Timestamp, + }, + /// 转账恢复 + TransferResumed { + constitutional_receipt: Hash, + timestamp: Timestamp, + }, +} + +// ======================== +// 主结构体 +// ======================== + +/// ACC-20 生产级别同质化代币协议 +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ACC20Token { - /// 代币名称 + // 协议标识 + pub protocol_uid: String, + pub lens_protocol_vector: String, + + // 代币基本信息 pub name: String, - - /// 代币符号 pub symbol: String, - - /// 小数位数 pub decimals: u8, - - /// 总供应量 pub total_supply: u128, - - /// 合约地址 - pub contract_address: Address, - - /// 余额映射 - pub balances: HashMap, - - /// 授权映射 (owner -> spender -> amount) - pub allowances: HashMap>, - - /// 创建时间 + pub supply_cap: Option, + + // 核心状态(NAC 原生:holdings 而非 balances) + pub holdings: HashMap, + /// 主权授权(NAC 原生:sovereignty_authorizations 而非 allowances) + pub sovereignty_authorizations: HashMap>, + + // 合规控制 + pub frozen_accounts: HashMap, + pub transfer_halted: bool, + pub halt_reason: Option, + + // 权限 + pub owner: Address, + pub minters: Vec
, + + // 待广播事件 + pub pending_events: Vec, + + // 时间戳 pub created_at: Timestamp, + pub updated_at: Timestamp, } impl ACC20Token { - /// 创建新的ACC-20代币 - pub fn new(name: String, symbol: String, decimals: u8, total_supply: u128) -> Self { - Self { + /// 创建新的 ACC-20 代币 + pub fn new( + name: String, + symbol: String, + decimals: u8, + owner: Address, + initial_supply: u128, + supply_cap: Option, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if let Some(cap) = supply_cap { + if initial_supply > cap { + return Err(ACC20Error::SupplyCapExceeded { + cap, + current: 0, + requested: initial_supply, + }); + } + } + + let mut holdings = HashMap::new(); + if initial_supply > 0 { + holdings.insert(owner.clone(), initial_supply); + } + + let mut token = Self { + protocol_uid: "nac.acc.ACC20Token.v2".to_string(), + lens_protocol_vector: "ACC-20".to_string(), name, symbol, decimals, - total_supply, - contract_address: Address::zero(), - balances: HashMap::new(), - allowances: HashMap::new(), - created_at: Timestamp::now(), + total_supply: initial_supply, + supply_cap, + holdings, + sovereignty_authorizations: HashMap::new(), + frozen_accounts: HashMap::new(), + transfer_halted: false, + halt_reason: None, + owner: owner.clone(), + minters: vec![owner.clone()], + pending_events: Vec::new(), + created_at: timestamp.clone(), + updated_at: timestamp.clone(), + }; + + if initial_supply > 0 { + token.pending_events.push(ACC20Event::Mint { + to: owner, + amount: initial_supply, + constitutional_receipt, + timestamp, + }); } + + Ok(token) } - - /// 获取余额 - pub fn balance_of(&self, owner: &Address) -> u128 { - *self.balances.get(owner).unwrap_or(&0) + + // ======================== + // 查询方法 + // ======================== + + /// 查询持仓余额 + pub fn balance_of(&self, holder: &Address) -> u128 { + self.holdings.get(holder).copied().unwrap_or(0) } - - /// 转账 - pub fn transfer(&mut self, from: &Address, to: &Address, amount: u128) -> Result<(), String> { - let from_balance = self.balance_of(from); - if from_balance < amount { - return Err("Insufficient balance".to_string()); - } - - self.balances.insert(*from, from_balance - amount); - let to_balance = self.balance_of(to); - self.balances.insert(*to, to_balance + amount); - - Ok(()) - } - - /// 授权 - pub fn approve(&mut self, owner: &Address, spender: &Address, amount: u128) { - self.allowances - .entry(*owner) - .or_insert_with(HashMap::new) - .insert(*spender, amount); - } - - /// 获取授权额度 + + /// 查询主权授权额度 pub fn allowance(&self, owner: &Address, spender: &Address) -> u128 { - self.allowances + self.sovereignty_authorizations .get(owner) - .and_then(|spenders| spenders.get(spender)) + .and_then(|m| m.get(spender)) .copied() .unwrap_or(0) } - - /// 从授权额度转账 + + /// 检查账户是否冻结 + pub fn is_frozen(&self, account: &Address) -> bool { + self.frozen_accounts.contains_key(account) + } + + // ======================== + // 转账方法 + // ======================== + + /// 直接转账 + pub fn transfer( + &mut self, + from: &Address, + to: &Address, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if amount == 0 { + return Err(ACC20Error::ZeroAmount); + } + if self.transfer_halted { + return Err(ACC20Error::TransferHalted); + } + if self.is_frozen(from) { + return Err(ACC20Error::AccountFrozen(from.clone())); + } + if self.is_frozen(to) { + return Err(ACC20Error::AccountFrozen(to.clone())); + } + + let from_balance = self.balance_of(from); + if from_balance < amount { + return Err(ACC20Error::InsufficientBalance { + holder: from.clone(), + required: amount, + available: from_balance, + }); + } + + *self.holdings.get_mut(from).unwrap() -= amount; + *self.holdings.entry(to.clone()).or_insert(0) += amount; + + self.pending_events.push(ACC20Event::Transfer { + from: from.clone(), + to: to.clone(), + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); + Ok(()) + } + + /// 代理转账(消耗授权额度) pub fn transfer_from( &mut self, spender: &Address, from: &Address, to: &Address, amount: u128, - ) -> Result<(), String> { - let allowed = self.allowance(from, spender); - if allowed < amount { - return Err("Insufficient allowance".to_string()); + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); } - - self.transfer(from, to, amount)?; - self.approve(from, spender, allowed - amount); - + if amount == 0 { + return Err(ACC20Error::ZeroAmount); + } + if self.transfer_halted { + return Err(ACC20Error::TransferHalted); + } + if self.is_frozen(from) { + return Err(ACC20Error::AccountFrozen(from.clone())); + } + if self.is_frozen(to) { + return Err(ACC20Error::AccountFrozen(to.clone())); + } + + let current_allowance = self.allowance(from, spender); + if current_allowance < amount { + return Err(ACC20Error::InsufficientAllowance { + owner: from.clone(), + spender: spender.clone(), + required: amount, + available: current_allowance, + }); + } + + let from_balance = self.balance_of(from); + if from_balance < amount { + return Err(ACC20Error::InsufficientBalance { + holder: from.clone(), + required: amount, + available: from_balance, + }); + } + + // 扣减授权额度 + *self.sovereignty_authorizations + .get_mut(from) + .unwrap() + .get_mut(spender) + .unwrap() -= amount; + + // 执行转账 + *self.holdings.get_mut(from).unwrap() -= amount; + *self.holdings.entry(to.clone()).or_insert(0) += amount; + + self.pending_events.push(ACC20Event::Transfer { + from: from.clone(), + to: to.clone(), + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); Ok(()) } - + + // ======================== + // 授权方法 + // ======================== + + /// 设置主权授权额度 + pub fn approve( + &mut self, + owner: &Address, + spender: &Address, + amount: u128, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if self.is_frozen(owner) { + return Err(ACC20Error::AccountFrozen(owner.clone())); + } + + self.sovereignty_authorizations + .entry(owner.clone()) + .or_insert_with(HashMap::new) + .insert(spender.clone(), amount); + + self.pending_events.push(ACC20Event::Approval { + owner: owner.clone(), + spender: spender.clone(), + amount, + timestamp, + }); + Ok(()) + } + + // ======================== + // 铸造/销毁方法 + // ======================== + /// 铸造代币 - pub fn mint(&mut self, to: &Address, amount: u128) -> Result<(), String> { - let balance = self.balance_of(to); - self.balances.insert(*to, balance + amount); - self.total_supply += amount; + pub fn mint( + &mut self, + minter: &Address, + to: &Address, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if amount == 0 { + return Err(ACC20Error::ZeroAmount); + } + if !self.minters.contains(minter) { + return Err(ACC20Error::Unauthorized(minter.clone())); + } + if self.is_frozen(to) { + return Err(ACC20Error::AccountFrozen(to.clone())); + } + + if let Some(cap) = self.supply_cap { + if self.total_supply.saturating_add(amount) > cap { + return Err(ACC20Error::SupplyCapExceeded { + cap, + current: self.total_supply, + requested: amount, + }); + } + } + + self.total_supply = self.total_supply.saturating_add(amount); + *self.holdings.entry(to.clone()).or_insert(0) += amount; + + self.pending_events.push(ACC20Event::Mint { + to: to.clone(), + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); Ok(()) } - + /// 销毁代币 - pub fn burn(&mut self, from: &Address, amount: u128) -> Result<(), String> { + pub fn burn( + &mut self, + from: &Address, + amount: u128, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if amount == 0 { + return Err(ACC20Error::ZeroAmount); + } + let balance = self.balance_of(from); if balance < amount { - return Err("Insufficient balance to burn".to_string()); + return Err(ACC20Error::InsufficientBalance { + holder: from.clone(), + required: amount, + available: balance, + }); } - - self.balances.insert(*from, balance - amount); - self.total_supply -= amount; + + *self.holdings.get_mut(from).unwrap() -= amount; + self.total_supply = self.total_supply.saturating_sub(amount); + + self.pending_events.push(ACC20Event::Burn { + from: from.clone(), + amount, + constitutional_receipt, + timestamp, + }); + self.updated_at = Timestamp::now(); Ok(()) } + + // ======================== + // 合规控制方法 + // ======================== + + /// 冻结账户 + pub fn freeze_account( + &mut self, + caller: &Address, + account: &Address, + reason: String, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if caller != &self.owner { + return Err(ACC20Error::Unauthorized(caller.clone())); + } + + self.frozen_accounts.insert(account.clone(), reason.clone()); + self.pending_events.push(ACC20Event::AccountFrozen { + account: account.clone(), + reason, + constitutional_receipt, + timestamp, + }); + Ok(()) + } + + /// 解冻账户 + pub fn unfreeze_account( + &mut self, + caller: &Address, + account: &Address, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if caller != &self.owner { + return Err(ACC20Error::Unauthorized(caller.clone())); + } + + self.frozen_accounts.remove(account); + self.pending_events.push(ACC20Event::AccountUnfrozen { + account: account.clone(), + constitutional_receipt, + timestamp, + }); + Ok(()) + } + + /// 暂停所有转账 + pub fn halt_transfers( + &mut self, + caller: &Address, + reason: String, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if caller != &self.owner { + return Err(ACC20Error::Unauthorized(caller.clone())); + } + + self.transfer_halted = true; + self.halt_reason = Some(reason.clone()); + self.pending_events.push(ACC20Event::TransferHalted { + reason, + constitutional_receipt, + timestamp, + }); + Ok(()) + } + + /// 恢复所有转账 + pub fn resume_transfers( + &mut self, + caller: &Address, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACC20Error> { + if constitutional_receipt.is_zero() { + return Err(ACC20Error::InvalidConstitutionalReceipt); + } + if caller != &self.owner { + return Err(ACC20Error::Unauthorized(caller.clone())); + } + + self.transfer_halted = false; + self.halt_reason = None; + self.pending_events.push(ACC20Event::TransferResumed { + constitutional_receipt, + timestamp, + }); + Ok(()) + } + + /// 添加铸造者 + pub fn add_minter( + &mut self, + caller: &Address, + minter: Address, + ) -> Result<(), ACC20Error> { + if caller != &self.owner { + return Err(ACC20Error::Unauthorized(caller.clone())); + } + if !self.minters.contains(&minter) { + self.minters.push(minter); + } + Ok(()) + } + + /// 排空待广播事件 + pub fn drain_pending_events(&mut self) -> Vec { + std::mem::take(&mut self.pending_events) + } } #[cfg(test)] mod tests { use super::*; - - + + fn make_addr(b: u8) -> Address { Address::new([b; 32]) } + fn make_hash(b: u8) -> Hash { Hash::sha3_384(&[b; 48]) } #[test] fn test_acc20_creation() { - let token = ACC20Token::new("Test Token".to_string(), "TEST".to_string(), 18, 1_000_000); - assert_eq!(token.name, "Test Token"); - assert_eq!(token.symbol, "TEST"); - assert_eq!(token.decimals, 18); - assert_eq!(token.total_supply, 1_000_000); + let owner = make_addr(1); + let receipt = make_hash(9); + let ts = Timestamp::now(); + let token = ACC20Token::new( + "NAC Test Token".to_string(), + "NTT".to_string(), + 18, + owner.clone(), + 1_000_000 * 10u128.pow(18), + Some(10_000_000 * 10u128.pow(18)), + receipt, + ts, + ).unwrap(); + assert_eq!(token.balance_of(&owner), 1_000_000 * 10u128.pow(18)); + assert_eq!(token.total_supply, 1_000_000 * 10u128.pow(18)); } #[test] - fn test_acc20_transfer() { - let mut token = ACC20Token::new("Test".to_string(), "TST".to_string(), 18, 1_000_000); - let addr1 = Address::new([1u8; 32]); - let addr2 = Address::new([2u8; 32]); - - token.mint(&addr1, 1000).unwrap(); - assert_eq!(token.balance_of(&addr1), 1000); - - token.transfer(&addr1, &addr2, 500).unwrap(); - assert_eq!(token.balance_of(&addr1), 500); - assert_eq!(token.balance_of(&addr2), 500); + fn test_transfer() { + let owner = make_addr(1); + let receiver = make_addr(2); + let receipt = make_hash(9); + let ts = Timestamp::now(); + let mut token = ACC20Token::new( + "Test".to_string(), "TST".to_string(), 18, + owner.clone(), 1000, None, receipt.clone(), ts.clone(), + ).unwrap(); + + token.transfer(&owner, &receiver, 300, receipt, ts).unwrap(); + assert_eq!(token.balance_of(&owner), 700); + assert_eq!(token.balance_of(&receiver), 300); + } + + #[test] + fn test_freeze_prevents_transfer() { + let owner = make_addr(1); + let victim = make_addr(2); + let receipt = make_hash(9); + let ts = Timestamp::now(); + let mut token = ACC20Token::new( + "Test".to_string(), "TST".to_string(), 18, + owner.clone(), 1000, None, receipt.clone(), ts.clone(), + ).unwrap(); + token.transfer(&owner, &victim, 500, receipt.clone(), ts.clone()).unwrap(); + token.freeze_account(&owner, &victim, "AML".to_string(), receipt.clone(), ts.clone()).unwrap(); + let result = token.transfer(&victim, &owner, 100, receipt, ts); + assert!(matches!(result, Err(ACC20Error::AccountFrozen(_)))); + } + + #[test] + fn test_supply_cap() { + let owner = make_addr(1); + let receipt = make_hash(9); + let ts = Timestamp::now(); + let mut token = ACC20Token::new( + "Test".to_string(), "TST".to_string(), 18, + owner.clone(), 900, Some(1000), receipt.clone(), ts.clone(), + ).unwrap(); + // 铸造到上限 + token.mint(&owner, &owner, 100, receipt.clone(), ts.clone()).unwrap(); + // 超出上限 + let result = token.mint(&owner, &owner, 1, receipt, ts); + assert!(matches!(result, Err(ACC20Error::SupplyCapExceeded { .. }))); } } diff --git a/nac-udm/src/l1_protocol/acc/acc_compliance.rs b/nac-udm/src/l1_protocol/acc/acc_compliance.rs index b910239..14686d5 100644 --- a/nac-udm/src/l1_protocol/acc/acc_compliance.rs +++ b/nac-udm/src/l1_protocol/acc/acc_compliance.rs @@ -58,6 +58,7 @@ impl SevenLayerComplianceResult { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ComplianceRecord { + pub layer_results: Vec, pub entity: Address, pub kyc_verified: bool, pub aml_cleared: bool, @@ -114,7 +115,7 @@ impl ACCComplianceProtocol { let compliance_hash = Hash::sha3_384(&data); let record = ComplianceRecord { entity: entity.clone(), kyc_verified, aml_cleared, - allowed_jurisdictions, blacklisted: false, ai_risk_score, + allowed_jurisdictions, blacklisted: false, ai_risk_score, layer_results: vec![false; 7], last_checked: timestamp.clone(), compliance_hash, }; self.compliance_records.insert(entity.clone(), record); @@ -175,3 +176,71 @@ impl ACCComplianceProtocol { pub fn get_record(&self, entity: &Address) -> Option<&ComplianceRecord> { self.compliance_records.get(entity) } pub fn drain_pending_events(&mut self) -> Vec { std::mem::take(&mut self.pending_events) } } + +impl ACCComplianceProtocol { + /// 批量合规检查 + pub fn batch_check(&mut self, entities: &[Address]) -> Vec<(Address, bool)> { + entities.iter().map(|e| (e.clone(), self.is_compliant(e))).collect() + } + + /// 获取合规历史(所有记录) + pub fn get_all_records(&self) -> Vec<&ComplianceRecord> { + self.compliance_records.values().collect() + } + + /// 获取不合规实体列表 + pub fn get_non_compliant_entities(&self) -> Vec<&Address> { + self.compliance_records.iter() + .filter(|(_, r)| !r.layer_results.iter().all(|&x| x)) + .map(|(a, _)| a) + .collect() + } + + /// 更新单层合规状态 + pub fn update_layer_result( + &mut self, + entity: &Address, + layer_index: usize, + passed: bool, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACCComplianceError> { + if constitutional_receipt.is_zero() { + return Err(ACCComplianceError::InvalidConstitutionalReceipt); + } + let record = self.compliance_records.get_mut(entity) + .ok_or_else(|| ACCComplianceError::EntityNotFound(entity.clone()))?; + if layer_index < record.layer_results.len() { + record.layer_results[layer_index] = passed; + record.last_checked = timestamp; + } + Ok(()) + } + + /// 移除黑名单 + pub fn remove_from_blacklist( + &mut self, + _caller: &Address, + entity: &Address, + constitutional_receipt: Hash, + ) -> Result<(), ACCComplianceError> { + if constitutional_receipt.is_zero() { + return Err(ACCComplianceError::InvalidConstitutionalReceipt); + } + self.blacklist.retain(|k, _| k != entity); + Ok(()) + } + + /// 检查是否在黑名单 + pub fn is_blacklisted(&self, entity: &Address) -> bool { + self.blacklist.contains_key(entity) + } + + /// 获取合规统计 + pub fn get_stats(&self) -> (usize, usize, usize) { + let total = self.compliance_records.len(); + let compliant = self.compliance_records.values().filter(|r| r.layer_results.iter().all(|&x| x)).count(); + let blacklisted = self.blacklist.len(); + (total, compliant, blacklisted) + } +} diff --git a/nac-udm/src/l1_protocol/acc/acc_redemption.rs b/nac-udm/src/l1_protocol/acc/acc_redemption.rs index e8a9ca1..9602b73 100644 --- a/nac-udm/src/l1_protocol/acc/acc_redemption.rs +++ b/nac-udm/src/l1_protocol/acc/acc_redemption.rs @@ -117,3 +117,50 @@ impl ACCRedemptionProtocol { 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() + } +} diff --git a/nac-udm/src/l1_protocol/acc/acc_reserve.rs b/nac-udm/src/l1_protocol/acc/acc_reserve.rs index a1710f1..e65b7a0 100644 --- a/nac-udm/src/l1_protocol/acc/acc_reserve.rs +++ b/nac-udm/src/l1_protocol/acc/acc_reserve.rs @@ -26,6 +26,9 @@ impl std::fmt::Display for ACCReserveError { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ReserveEntry { + pub locked: bool, + pub lock_reason: Option, + pub value_xtzh: u128, pub asset_symbol: String, pub amount: u128, pub custodian: Address, @@ -74,6 +77,7 @@ impl ACCReserveProtocol { asset_symbol: asset_symbol.clone(), amount: 0, custodian: custodian.clone(), last_audited: timestamp.clone(), audit_hash: Hash::zero(), + locked: false, lock_reason: None, value_xtzh: 0, }); entry.amount = entry.amount.saturating_add(amount); entry.custodian = custodian.clone(); @@ -108,5 +112,62 @@ impl ACCReserveProtocol { } pub fn get_reserve(&self, asset: &str) -> Option<&ReserveEntry> { self.reserves.get(asset) } pub fn total_reserve_count(&self) -> usize { self.reserves.len() } - pub fn drain_pending_events(&mut self) -> Vec { std::mem::take(&mut self.pending_events) } + pub fn drain_events(&mut self) -> Vec { std::mem::take(&mut self.pending_events) } +} + +impl ACCReserveProtocol { + /// 计算储备率(BPS,10000 = 100%) + pub fn calculate_reserve_ratio(&self, asset: &str, required_amount: u128) -> u32 { + if required_amount == 0 { return 10000; } + let actual = self.reserves.get(asset).map(|r| r.amount).unwrap_or(0); + ((actual as u64 * 10000) / required_amount as u64) as u32 + } + + /// 获取所有储备条目 + pub fn get_all_reserves(&self) -> Vec<(&String, &ReserveEntry)> { + self.reserves.iter().collect() + } + + /// 紧急锁定储备(禁止提取) + pub fn emergency_lock( + &mut self, + asset: &str, + reason: String, + constitutional_receipt: Hash, + ) -> Result<(), ACCReserveError> { + if constitutional_receipt.is_zero() { + return Err(ACCReserveError::InvalidConstitutionalReceipt); + } + if let Some(entry) = self.reserves.get_mut(asset) { + entry.locked = true; + entry.lock_reason = Some(reason); + } + Ok(()) + } + + /// 解锁储备 + pub fn unlock_reserve( + &mut self, + asset: &str, + constitutional_receipt: Hash, + ) -> Result<(), ACCReserveError> { + if constitutional_receipt.is_zero() { + return Err(ACCReserveError::InvalidConstitutionalReceipt); + } + if let Some(entry) = self.reserves.get_mut(asset) { + entry.locked = false; + entry.lock_reason = None; + } + Ok(()) + } + + /// 获取总储备价值(XTZH) + pub fn total_reserve_value_xtzh(&self) -> u128 { + self.reserves.values().map(|r| r.value_xtzh).sum() + } + + /// 检查储备是否充足 + pub fn is_reserve_sufficient(&self, asset: &str, required: u128) -> bool { + self.reserves.get(asset).map(|r| r.amount >= required && !r.locked).unwrap_or(false) + } } diff --git a/nac-udm/src/l1_protocol/acc/acc_rwa.rs b/nac-udm/src/l1_protocol/acc/acc_rwa.rs index cf0191a..9bbcfea 100644 --- a/nac-udm/src/l1_protocol/acc/acc_rwa.rs +++ b/nac-udm/src/l1_protocol/acc/acc_rwa.rs @@ -175,3 +175,81 @@ impl ACCRWAProtocol { } pub fn drain_pending_events(&mut self) -> Vec { std::mem::take(&mut self.pending_events) } } + +impl ACCRWAProtocol { + /// 查询所有资产列表 + pub fn get_all_assets(&self) -> Vec<&RWAAssetRecord> { + self.assets.values().collect() + } + + /// 按司法管辖区查询资产 + pub fn get_assets_by_jurisdiction(&self, jurisdiction: &str) -> Vec<&RWAAssetRecord> { + self.assets.values() + .filter(|a| a.jurisdiction == jurisdiction) + .collect() + } + + /// 按 GNACS 编码查询资产 + pub fn get_assets_by_gnacs(&self, gnacs_prefix: &str) -> Vec<&RWAAssetRecord> { + self.assets.values() + .filter(|a| a.gnacs_code.starts_with(gnacs_prefix)) + .collect() + } + + /// 更新资产 AI 合规分数 + pub fn update_compliance_score( + &mut self, + asset_id: &Hash, + new_score: u8, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACCRWAError> { + if constitutional_receipt.is_zero() { + return Err(ACCRWAError::InvalidConstitutionalReceipt); + } + let asset = self.assets.get_mut(asset_id) + .ok_or(ACCRWAError::AssetNotFound(Hash::zero()))?; + asset.ai_compliance_score = new_score; + self.pending_events.push(RWAProtocolEvent::ValuationUpdated { + asset_id: asset_id.clone(), + old_value: asset.current_valuation_xtzh, + new_value: asset.current_valuation_xtzh, + timestamp, + }); + Ok(()) + } + + /// 取消资产转移(恢复持有者) + pub fn cancel_transfer( + &mut self, + asset_id: &Hash, + original_holder: Address, + constitutional_receipt: Hash, + timestamp: Timestamp, + ) -> Result<(), ACCRWAError> { + if constitutional_receipt.is_zero() { + return Err(ACCRWAError::InvalidConstitutionalReceipt); + } + let _asset = self.assets.get_mut(asset_id) + .ok_or(ACCRWAError::AssetNotFound(Hash::zero()))?; + let holdings = self.holdings.entry(asset_id.clone()).or_default(); + let current_holder = holdings.iter() + .find(|(_, &v)| v > 0) + .map(|(k, _)| k.clone()); + if let Some(current) = current_holder { + let amount = holdings.remove(¤t).unwrap_or(0); + *holdings.entry(original_holder.clone()).or_insert(0) += amount; + } + Ok(()) + } + + /// 获取资产总数 + pub fn total_assets(&self) -> usize { + self.assets.len() + } + + /// 检查资产是否存在 + pub fn asset_exists(&self, asset_id: &Hash) -> bool { + self.assets.contains_key(asset_id) + } +}