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

335 lines
8.9 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-1155: 多类型资产协议Multi-Token Protocol
//
// NAC原生的多类型资产标准专为RWA资产设计
// 不是ERC-1155的实现是完全独立的NAC原生协议
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// ACC-1155错误类型
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ACC1155Error {
/// 余额不足
InsufficientBalance,
/// 无效的接收地址
InvalidRecipient,
/// 无效的金额
InvalidAmount,
/// 资产类型不存在
TokenTypeNotFound,
/// 未授权操作
Unauthorized,
}
/// ACC-1155资产状态
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ACC1155State {
/// 账户余额映射 (account -> token_id -> balance)
pub balances: HashMap<String, HashMap<String, u128>>,
/// 操作员授权映射 (owner -> operator -> bool)
pub operator_approvals: HashMap<String, HashMap<String, bool>>,
/// 资产URI映射 (token_id -> uri)
pub token_uris: HashMap<String, String>,
}
/// ACC-1155接口
pub trait ACC1155 {
/// 获取账户指定资产类型的余额
fn balance_of(&self, account: &str, token_id: &str) -> u128;
/// 批量获取余额
fn balance_of_batch(&self, accounts: &[String], token_ids: &[String]) -> Vec<u128>;
/// 转移资产
fn safe_transfer_from(
&mut self,
from: &str,
to: &str,
token_id: &str,
amount: u128,
) -> Result<(), ACC1155Error>;
/// 批量转移资产
fn safe_batch_transfer_from(
&mut self,
from: &str,
to: &str,
token_ids: &[String],
amounts: &[u128],
) -> Result<(), ACC1155Error>;
/// 设置操作员授权
fn set_approval_for_all(
&mut self,
owner: &str,
operator: &str,
approved: bool,
) -> Result<(), ACC1155Error>;
/// 检查操作员授权
fn is_approved_for_all(&self, owner: &str, operator: &str) -> bool;
/// 铸造资产
fn mint(&mut self, to: &str, token_id: &str, amount: u128) -> Result<(), ACC1155Error>;
/// 批量铸造资产
fn mint_batch(
&mut self,
to: &str,
token_ids: &[String],
amounts: &[u128],
) -> Result<(), ACC1155Error>;
/// 销毁资产
fn burn(&mut self, from: &str, token_id: &str, amount: u128) -> Result<(), ACC1155Error>;
/// 获取资产URI
fn uri(&self, token_id: &str) -> Option<String>;
}
/// ACC-1155标准实现
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ACC1155Token {
state: ACC1155State,
}
impl ACC1155Token {
/// 创建新的ACC-1155资产集合
pub fn new() -> Self {
Self {
state: ACC1155State {
balances: HashMap::new(),
operator_approvals: HashMap::new(),
token_uris: HashMap::new(),
},
}
}
/// 获取状态的可变引用
pub fn state_mut(&mut self) -> &mut ACC1155State {
&mut self.state
}
/// 获取状态的不可变引用
pub fn state(&self) -> &ACC1155State {
&self.state
}
}
impl Default for ACC1155Token {
fn default() -> Self {
Self::new()
}
}
impl ACC1155 for ACC1155Token {
fn balance_of(&self, account: &str, token_id: &str) -> u128 {
self.state
.balances
.get(account)
.and_then(|tokens| tokens.get(token_id))
.copied()
.unwrap_or(0)
}
fn balance_of_batch(&self, accounts: &[String], token_ids: &[String]) -> Vec<u128> {
accounts
.iter()
.zip(token_ids.iter())
.map(|(account, token_id)| self.balance_of(account, token_id))
.collect()
}
fn safe_transfer_from(
&mut self,
from: &str,
to: &str,
token_id: &str,
amount: u128,
) -> Result<(), ACC1155Error> {
if amount == 0 {
return Err(ACC1155Error::InvalidAmount);
}
let from_balance = self.balance_of(from, token_id);
if from_balance < amount {
return Err(ACC1155Error::InsufficientBalance);
}
// 更新发送方余额
self.state
.balances
.entry(from.to_string())
.or_insert_with(HashMap::new)
.insert(token_id.to_string(), from_balance - amount);
// 更新接收方余额
let to_balance = self.balance_of(to, token_id);
self.state
.balances
.entry(to.to_string())
.or_insert_with(HashMap::new)
.insert(token_id.to_string(), to_balance + amount);
Ok(())
}
fn safe_batch_transfer_from(
&mut self,
from: &str,
to: &str,
token_ids: &[String],
amounts: &[u128],
) -> Result<(), ACC1155Error> {
if token_ids.len() != amounts.len() {
return Err(ACC1155Error::InvalidAmount);
}
for (token_id, &amount) in token_ids.iter().zip(amounts.iter()) {
self.safe_transfer_from(from, to, token_id, amount)?;
}
Ok(())
}
fn set_approval_for_all(
&mut self,
owner: &str,
operator: &str,
approved: bool,
) -> Result<(), ACC1155Error> {
self.state
.operator_approvals
.entry(owner.to_string())
.or_insert_with(HashMap::new)
.insert(operator.to_string(), approved);
Ok(())
}
fn is_approved_for_all(&self, owner: &str, operator: &str) -> bool {
self.state
.operator_approvals
.get(owner)
.and_then(|approvals| approvals.get(operator))
.copied()
.unwrap_or(false)
}
fn mint(&mut self, to: &str, token_id: &str, amount: u128) -> Result<(), ACC1155Error> {
let to_balance = self.balance_of(to, token_id);
self.state
.balances
.entry(to.to_string())
.or_insert_with(HashMap::new)
.insert(token_id.to_string(), to_balance + amount);
Ok(())
}
fn mint_batch(
&mut self,
to: &str,
token_ids: &[String],
amounts: &[u128],
) -> Result<(), ACC1155Error> {
if token_ids.len() != amounts.len() {
return Err(ACC1155Error::InvalidAmount);
}
for (token_id, &amount) in token_ids.iter().zip(amounts.iter()) {
self.mint(to, token_id, amount)?;
}
Ok(())
}
fn burn(&mut self, from: &str, token_id: &str, amount: u128) -> Result<(), ACC1155Error> {
let from_balance = self.balance_of(from, token_id);
if from_balance < amount {
return Err(ACC1155Error::InsufficientBalance);
}
self.state
.balances
.entry(from.to_string())
.or_insert_with(HashMap::new)
.insert(token_id.to_string(), from_balance - amount);
Ok(())
}
fn uri(&self, token_id: &str) -> Option<String> {
self.state.token_uris.get(token_id).cloned()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mint_and_balance() {
let mut token = ACC1155Token::new();
assert!(token.mint("alice", "1", 1000).is_ok());
assert_eq!(token.balance_of("alice", "1"), 1000);
}
#[test]
fn test_transfer() {
let mut token = ACC1155Token::new();
token.mint("alice", "1", 1000).unwrap();
assert!(token.safe_transfer_from("alice", "bob", "1", 500).is_ok());
assert_eq!(token.balance_of("alice", "1"), 500);
assert_eq!(token.balance_of("bob", "1"), 500);
}
#[test]
fn test_batch_transfer() {
let mut token = ACC1155Token::new();
token.mint("alice", "1", 1000).unwrap();
token.mint("alice", "2", 2000).unwrap();
let token_ids = vec!["1".to_string(), "2".to_string()];
let amounts = vec![500, 1000];
assert!(token
.safe_batch_transfer_from("alice", "bob", &token_ids, &amounts)
.is_ok());
assert_eq!(token.balance_of("alice", "1"), 500);
assert_eq!(token.balance_of("alice", "2"), 1000);
assert_eq!(token.balance_of("bob", "1"), 500);
assert_eq!(token.balance_of("bob", "2"), 1000);
}
#[test]
fn test_burn() {
let mut token = ACC1155Token::new();
token.mint("alice", "1", 1000).unwrap();
assert!(token.burn("alice", "1", 500).is_ok());
assert_eq!(token.balance_of("alice", "1"), 500);
}
#[test]
fn test_approval() {
let mut token = ACC1155Token::new();
assert!(token
.set_approval_for_all("alice", "bob", true)
.is_ok());
assert!(token.is_approved_for_all("alice", "bob"));
assert!(token
.set_approval_for_all("alice", "bob", false)
.is_ok());
assert!(!token.is_approved_for_all("alice", "bob"));
}
}