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

419 lines
11 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-20: 可替代资产协议Fungible Token Protocol
//
// NAC原生的可替代资产标准专为RWA资产设计
// 不是ERC-20的实现是完全独立的NAC原生协议
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// ACC-20错误类型
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ACC20Error {
/// 余额不足
InsufficientBalance,
/// 授权额度不足
InsufficientAllowance,
/// 无效的接收地址
InvalidRecipient,
/// 无效的金额
InvalidAmount,
/// 资产已冻结
AssetFrozen,
/// 未授权操作
Unauthorized,
/// 合规检查失败
ComplianceFailed(String),
}
/// ACC-20资产元数据
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ACC20Metadata {
/// 资产名称
pub name: String,
/// 资产符号
pub symbol: String,
/// 小数位数
pub decimals: u8,
/// 总供应量
pub total_supply: u128,
/// 资产DNANAC原生
pub asset_dna: Option<String>,
/// GNACS分类编码NAC原生
pub gnacs_code: Option<String>,
/// 是否可铸造
pub mintable: bool,
/// 是否可销毁
pub burnable: bool,
}
/// ACC-20资产状态
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ACC20State {
/// 账户余额映射
pub balances: HashMap<String, u128>,
/// 授权额度映射 (owner -> spender -> amount)
pub allowances: HashMap<String, HashMap<String, u128>>,
/// 冻结账户列表
pub frozen_accounts: Vec<String>,
/// 元数据
pub metadata: ACC20Metadata,
}
/// ACC-20接口
pub trait ACC20 {
/// 获取资产名称
fn name(&self) -> String;
/// 获取资产符号
fn symbol(&self) -> String;
/// 获取小数位数
fn decimals(&self) -> u8;
/// 获取总供应量
fn total_supply(&self) -> u128;
/// 获取账户余额
fn balance_of(&self, account: &str) -> u128;
/// 转账
fn transfer(&mut self, from: &str, to: &str, amount: u128) -> Result<(), ACC20Error>;
/// 授权
fn approve(&mut self, owner: &str, spender: &str, amount: u128) -> Result<(), ACC20Error>;
/// 获取授权额度
fn allowance(&self, owner: &str, spender: &str) -> u128;
/// 从授权额度中转账
fn transfer_from(
&mut self,
spender: &str,
from: &str,
to: &str,
amount: u128,
) -> Result<(), ACC20Error>;
/// 铸造(仅限授权地址)
fn mint(&mut self, to: &str, amount: u128) -> Result<(), ACC20Error>;
/// 销毁
fn burn(&mut self, from: &str, amount: u128) -> Result<(), ACC20Error>;
/// 冻结账户
fn freeze_account(&mut self, account: &str) -> Result<(), ACC20Error>;
/// 解冻账户
fn unfreeze_account(&mut self, account: &str) -> Result<(), ACC20Error>;
/// 检查账户是否冻结
fn is_frozen(&self, account: &str) -> bool;
}
/// ACC-20标准实现
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ACC20Token {
state: ACC20State,
}
impl ACC20Token {
/// 创建新的ACC-20资产
pub fn new(metadata: ACC20Metadata) -> Self {
Self {
state: ACC20State {
balances: HashMap::new(),
allowances: HashMap::new(),
frozen_accounts: Vec::new(),
metadata,
},
}
}
/// 获取状态的可变引用
pub fn state_mut(&mut self) -> &mut ACC20State {
&mut self.state
}
/// 获取状态的不可变引用
pub fn state(&self) -> &ACC20State {
&self.state
}
}
impl ACC20 for ACC20Token {
fn name(&self) -> String {
self.state.metadata.name.clone()
}
fn symbol(&self) -> String {
self.state.metadata.symbol.clone()
}
fn decimals(&self) -> u8 {
self.state.metadata.decimals
}
fn total_supply(&self) -> u128 {
self.state.metadata.total_supply
}
fn balance_of(&self, account: &str) -> u128 {
*self.state.balances.get(account).unwrap_or(&0)
}
fn transfer(&mut self, from: &str, to: &str, amount: u128) -> Result<(), ACC20Error> {
// 检查账户是否冻结
if self.is_frozen(from) || self.is_frozen(to) {
return Err(ACC20Error::AssetFrozen);
}
// 检查金额有效性
if amount == 0 {
return Err(ACC20Error::InvalidAmount);
}
// 检查余额
let from_balance = self.balance_of(from);
if from_balance < amount {
return Err(ACC20Error::InsufficientBalance);
}
// 执行转账
self.state.balances.insert(from.to_string(), from_balance - amount);
let to_balance = self.balance_of(to);
self.state.balances.insert(to.to_string(), to_balance + amount);
Ok(())
}
fn approve(&mut self, owner: &str, spender: &str, amount: u128) -> Result<(), ACC20Error> {
// 检查账户是否冻结
if self.is_frozen(owner) || self.is_frozen(spender) {
return Err(ACC20Error::AssetFrozen);
}
// 设置授权额度
self.state
.allowances
.entry(owner.to_string())
.or_insert_with(HashMap::new)
.insert(spender.to_string(), amount);
Ok(())
}
fn allowance(&self, owner: &str, spender: &str) -> u128 {
self.state
.allowances
.get(owner)
.and_then(|allowances| allowances.get(spender))
.copied()
.unwrap_or(0)
}
fn transfer_from(
&mut self,
spender: &str,
from: &str,
to: &str,
amount: u128,
) -> Result<(), ACC20Error> {
// 检查账户是否冻结
if self.is_frozen(from) || self.is_frozen(to) || self.is_frozen(spender) {
return Err(ACC20Error::AssetFrozen);
}
// 检查授权额度
let current_allowance = self.allowance(from, spender);
if current_allowance < amount {
return Err(ACC20Error::InsufficientAllowance);
}
// 执行转账
self.transfer(from, to, amount)?;
// 减少授权额度
self.state
.allowances
.get_mut(from)
.unwrap()
.insert(spender.to_string(), current_allowance - amount);
Ok(())
}
fn mint(&mut self, to: &str, amount: u128) -> Result<(), ACC20Error> {
// 检查是否可铸造
if !self.state.metadata.mintable {
return Err(ACC20Error::Unauthorized);
}
// 检查账户是否冻结
if self.is_frozen(to) {
return Err(ACC20Error::AssetFrozen);
}
// 增加余额
let to_balance = self.balance_of(to);
self.state.balances.insert(to.to_string(), to_balance + amount);
// 增加总供应量
self.state.metadata.total_supply += amount;
Ok(())
}
fn burn(&mut self, from: &str, amount: u128) -> Result<(), ACC20Error> {
// 检查是否可销毁
if !self.state.metadata.burnable {
return Err(ACC20Error::Unauthorized);
}
// 检查账户是否冻结
if self.is_frozen(from) {
return Err(ACC20Error::AssetFrozen);
}
// 检查余额
let from_balance = self.balance_of(from);
if from_balance < amount {
return Err(ACC20Error::InsufficientBalance);
}
// 减少余额
self.state.balances.insert(from.to_string(), from_balance - amount);
// 减少总供应量
self.state.metadata.total_supply -= amount;
Ok(())
}
fn freeze_account(&mut self, account: &str) -> Result<(), ACC20Error> {
if !self.is_frozen(account) {
self.state.frozen_accounts.push(account.to_string());
}
Ok(())
}
fn unfreeze_account(&mut self, account: &str) -> Result<(), ACC20Error> {
self.state.frozen_accounts.retain(|a| a != account);
Ok(())
}
fn is_frozen(&self, account: &str) -> bool {
self.state.frozen_accounts.contains(&account.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_token() -> ACC20Token {
let metadata = ACC20Metadata {
name: "Test Token".to_string(),
symbol: "TEST".to_string(),
decimals: 18,
total_supply: 1000000,
asset_dna: None,
gnacs_code: None,
mintable: true,
burnable: true,
};
ACC20Token::new(metadata)
}
#[test]
fn test_metadata() {
let token = create_test_token();
assert_eq!(token.name(), "Test Token");
assert_eq!(token.symbol(), "TEST");
assert_eq!(token.decimals(), 18);
assert_eq!(token.total_supply(), 1000000);
}
#[test]
fn test_transfer() {
let mut token = create_test_token();
// 初始化账户余额
token.state_mut().balances.insert("alice".to_string(), 1000);
// 转账
assert!(token.transfer("alice", "bob", 500).is_ok());
assert_eq!(token.balance_of("alice"), 500);
assert_eq!(token.balance_of("bob"), 500);
// 余额不足
assert_eq!(
token.transfer("alice", "bob", 1000),
Err(ACC20Error::InsufficientBalance)
);
}
#[test]
fn test_approve_and_transfer_from() {
let mut token = create_test_token();
// 初始化账户余额
token.state_mut().balances.insert("alice".to_string(), 1000);
// 授权
assert!(token.approve("alice", "bob", 500).is_ok());
assert_eq!(token.allowance("alice", "bob"), 500);
// 从授权额度中转账
assert!(token.transfer_from("bob", "alice", "charlie", 300).is_ok());
assert_eq!(token.balance_of("alice"), 700);
assert_eq!(token.balance_of("charlie"), 300);
assert_eq!(token.allowance("alice", "bob"), 200);
// 授权额度不足
assert_eq!(
token.transfer_from("bob", "alice", "charlie", 300),
Err(ACC20Error::InsufficientAllowance)
);
}
#[test]
fn test_mint_and_burn() {
let mut token = create_test_token();
// 铸造
assert!(token.mint("alice", 1000).is_ok());
assert_eq!(token.balance_of("alice"), 1000);
assert_eq!(token.total_supply(), 1001000);
// 销毁
assert!(token.burn("alice", 500).is_ok());
assert_eq!(token.balance_of("alice"), 500);
assert_eq!(token.total_supply(), 1000500);
}
#[test]
fn test_freeze_and_unfreeze() {
let mut token = create_test_token();
// 初始化账户余额
token.state_mut().balances.insert("alice".to_string(), 1000);
// 冻结账户
assert!(token.freeze_account("alice").is_ok());
assert!(token.is_frozen("alice"));
// 冻结账户无法转账
assert_eq!(
token.transfer("alice", "bob", 500),
Err(ACC20Error::AssetFrozen)
);
// 解冻账户
assert!(token.unfreeze_account("alice").is_ok());
assert!(!token.is_frozen("alice"));
// 解冻后可以转账
assert!(token.transfer("alice", "bob", 500).is_ok());
}
}