//! ACC-20: NAC 原生同质化代币标准 //! 协议 UID: nac.acc.ACC20Token.v2 //! 完全基于 NAC 原生类型系统,无以太坊模式残留 use std::collections::HashMap; use serde::{Deserialize, Serialize}; use crate::primitives::{Address, Hash, Timestamp}; // ======================== // 错误类型 // ======================== #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] /// ACC20Error 错误类型 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 广播) // ======================== #[derive(Debug, Clone, Serialize, Deserialize)] /// ACC20Event 协议事件 pub enum ACC20Event { /// 代币转移 Transfer { /// 发送方账户地址 from: Address, /// 接收方账户地址 to: Address, /// 代币数量(最小单位) amount: u128, /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 授权额度变更 Approval { /// 所有者账户地址 owner: Address, /// 被授权方账户地址 spender: Address, /// 代币数量(最小单位) amount: u128, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 铸造 Mint { /// 接收方账户地址 to: Address, /// 代币数量(最小单位) amount: u128, /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 销毁 Burn { /// 发送方账户地址 from: Address, /// 代币数量(最小单位) amount: u128, /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 账户冻结 AccountFrozen { /// account 字段 account: Address, /// 操作原因说明 reason: String, /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 账户解冻 AccountUnfrozen { /// account 字段 account: Address, /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 转账暂停 TransferHalted { /// 操作原因说明 reason: String, /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, /// 转账恢复 TransferResumed { /// 宪法收据哈希(CBPP 共识凭证) constitutional_receipt: Hash, /// 操作时间戳(UTC Unix 毫秒) timestamp: Timestamp, }, } // ======================== // 主结构体 // ======================== /// ACC-20 生产级别同质化代币协议 #[derive(Debug, Clone, Serialize, Deserialize)] /// ACC20Token 代币协议实现 pub struct ACC20Token { // 协议标识 /// 协议唯一标识符 pub protocol_uid: String, /// NAC-Lens 协议向量 pub lens_protocol_vector: String, // 代币基本信息 /// 名称 pub name: String, /// 代币符号 pub symbol: String, /// 代币精度(小数位数) pub decimals: u8, /// 代币总供应量 pub total_supply: u128, /// 供应量上限(None 表示无上限) 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, /// 暂停原因(None 表示未暂停) pub halt_reason: Option, // 权限 /// 所有者账户地址 pub owner: Address, /// 铸造者地址列表 pub minters: Vec
, // 待广播事件 /// 待广播的 CSNP 协议事件队列 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, 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: 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, holder: &Address) -> u128 { self.holdings.get(holder).copied().unwrap_or(0) } /// 查询主权授权额度 pub fn allowance(&self, owner: &Address, spender: &Address) -> u128 { self.sovereignty_authorizations .get(owner) .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).expect("FIX-006: unexpected None/Err") -= 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, 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 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) .expect("FIX-006: unexpected None/Err") .get_mut(spender) .expect("FIX-006: unexpected None/Err") -= amount; // 执行转账 *self.holdings.get_mut(from).expect("FIX-006: unexpected None/Err") -= 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, 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, 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(ACC20Error::InsufficientBalance { holder: from.clone(), required: amount, available: balance, }); } *self.holdings.get_mut(from).expect("FIX-006: unexpected None/Err") -= 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 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, ).expect("FIX-006: unexpected None/Err"); 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_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(), ).expect("FIX-006: unexpected None/Err"); token.transfer(&owner, &receiver, 300, receipt, ts).expect("FIX-006: unexpected None/Err"); 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(), ).expect("FIX-006: unexpected None/Err"); token.transfer(&owner, &victim, 500, receipt.clone(), ts.clone()).expect("FIX-006: unexpected None/Err"); token.freeze_account(&owner, &victim, "AML".to_string(), receipt.clone(), ts.clone()).expect("FIX-006: unexpected None/Err"); 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(), ).expect("FIX-006: unexpected None/Err"); // 铸造到上限 token.mint(&owner, &owner, 100, receipt.clone(), ts.clone()).expect("FIX-006: unexpected None/Err"); // 超出上限 let result = token.mint(&owner, &owner, 1, receipt, ts); assert!(matches!(result, Err(ACC20Error::SupplyCapExceeded { .. }))); } } // ============================================================ // ACC-20 上层接口(供 nac-asset-onboarding 等模块使用) // ============================================================ /// ACC-20 代币部署请求 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TokenDeployRequest { /// 代币名称 pub name: String, /// 代币符号 pub symbol: String, /// 总供应量 pub total_supply: u128, /// 精度(小数位数) pub decimals: u8, /// GNACS 资产分类码 pub gnacs_code: String, /// 部署者地址(32 字节,NAC 原生地址格式) pub deployer: String, } /// ACC-20 代币元数据 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TokenMetadata { /// 合约地址(32 字节) pub contract_address: String, /// 代币名称 pub name: String, /// 代币符号 pub symbol: String, /// 总供应量 pub total_supply: u128, /// 精度 pub decimals: u8, /// 部署区块高度 pub deploy_block: u64, /// 部署交易哈希(SHA3-384,48 字节) pub deploy_tx_hash: String, } /// ACC-20 协议接口 pub struct ACC20Protocol; impl ACC20Protocol { /// 部署新的 ACC-20 代币合约 pub async fn deploy(&self, request: TokenDeployRequest) -> Result { // TODO: 通过 NVM 部署 Charter 合约 Ok(TokenMetadata { contract_address: format!("nac1{}", &request.name.to_lowercase()), name: request.name, symbol: request.symbol, total_supply: request.total_supply, decimals: request.decimals, deploy_block: 0, deploy_tx_hash: String::new(), }) } }