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

527 lines
16 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-XTZH: XTZH原生代币协议
// XTZH是NAC公链的原生资产稳定币具有双重价值锚定
// 1. 一级锚定RWA资产或合格跨链资产的价值
// 2. 二级锚定1.25倍黄金永续合约储备
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// XTZH代币信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XTZHToken {
/// 代币名称
pub name: String,
/// 代币符号
pub symbol: String,
/// 小数位数
pub decimals: u8,
/// 总供应量
pub total_supply: u128,
/// 流通供应量
pub circulating_supply: u128,
/// 黄金储备覆盖率GCR百分比100表示100%
pub gold_coverage_ratio: u16,
/// 最低黄金覆盖率宪法级参数需90%超级多数修改)
pub min_gold_coverage_ratio: u16,
}
/// XTZH账户余额
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XTZHBalance {
/// 可用余额
pub available: u128,
/// 锁定余额(用于铸造抵押)
pub locked: u128,
/// 冻结余额(用于清算)
pub frozen: u128,
}
/// XTZH转账记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XTZHTransfer {
/// 转账ID
pub transfer_id: String,
/// 发送方地址
pub from: String,
/// 接收方地址
pub to: String,
/// 转账金额
pub amount: u128,
/// 时间戳
pub timestamp: u64,
/// 交易哈希
pub tx_hash: String,
}
/// XTZH铸造记录
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XTZHMintRecord {
/// 铸造ID
pub mint_id: String,
/// 资产DNA哈希RWA资产或跨链资产
pub asset_dna_hash: String,
/// 资产类型RWA或CrossChain
pub asset_type: AssetType,
/// 铸造数量
pub amount: u128,
/// 所有者DID
pub owner_did: String,
/// 黄金储备锚定哈希
pub gold_reserve_anchor_hash: String,
/// 健康因子HF百分比100表示100%
pub health_factor: u16,
/// 铸造时间戳
pub timestamp: u64,
/// 状态
pub status: MintStatus,
}
/// 资产类型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AssetType {
/// RWA资产
RWA,
/// 跨链资产
CrossChain,
}
/// 铸造状态
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MintStatus {
/// 活跃
Active,
/// 预警HF < 1.1
Warning,
/// 清算中HF < 1.0
Liquidating,
/// 已赎回
Redeemed,
}
/// XTZH协议管理器
#[derive(Debug, Clone)]
pub struct XTZHProtocol {
/// XTZH代币信息
pub token: XTZHToken,
/// 账户余额映射(地址 -> 余额)
pub balances: HashMap<String, XTZHBalance>,
/// 铸造记录映射铸造ID -> 铸造记录)
pub mint_records: HashMap<String, XTZHMintRecord>,
/// 转账记录
pub transfers: Vec<XTZHTransfer>,
}
impl XTZHProtocol {
/// 创建新的XTZH协议实例
pub fn new() -> Self {
Self {
token: XTZHToken {
name: "XTZH".to_string(),
symbol: "XTZH".to_string(),
decimals: 8,
total_supply: 0,
circulating_supply: 0,
gold_coverage_ratio: 125, // 初始125%覆盖率
min_gold_coverage_ratio: 100, // 最低100%覆盖率
},
balances: HashMap::new(),
mint_records: HashMap::new(),
transfers: Vec::new(),
}
}
/// 获取账户余额
pub fn balance_of(&self, address: &str) -> XTZHBalance {
self.balances
.get(address)
.cloned()
.unwrap_or(XTZHBalance {
available: 0,
locked: 0,
frozen: 0,
})
}
/// 获取账户总余额
pub fn total_balance_of(&self, address: &str) -> u128 {
let balance = self.balance_of(address);
balance.available + balance.locked + balance.frozen
}
/// 转账
pub fn transfer(
&mut self,
from: &str,
to: &str,
amount: u128,
timestamp: u64,
) -> Result<String, String> {
// 检查发送方余额
let from_balance = self.balance_of(from);
if from_balance.available < amount {
return Err("Insufficient balance".to_string());
}
// 扣除发送方余额
let mut new_from_balance = from_balance.clone();
new_from_balance.available -= amount;
self.balances.insert(from.to_string(), new_from_balance);
// 增加接收方余额
let to_balance = self.balance_of(to);
let mut new_to_balance = to_balance.clone();
new_to_balance.available += amount;
self.balances.insert(to.to_string(), new_to_balance);
// 生成转账ID和交易哈希
let transfer_id = format!("transfer_{}", timestamp);
let tx_hash = format!("0x{:x}", timestamp);
// 记录转账
let transfer = XTZHTransfer {
transfer_id: transfer_id.clone(),
from: from.to_string(),
to: to.to_string(),
amount,
timestamp,
tx_hash,
};
self.transfers.push(transfer);
Ok(transfer_id)
}
/// 铸造XTZH内部方法由铸造协议调用
pub fn mint(
&mut self,
mint_id: &str,
asset_dna_hash: &str,
asset_type: AssetType,
amount: u128,
owner_did: &str,
gold_reserve_anchor_hash: &str,
timestamp: u64,
) -> Result<(), String> {
// 检查铸造ID是否已存在
if self.mint_records.contains_key(mint_id) {
return Err("Mint ID already exists".to_string());
}
// 创建铸造记录
let mint_record = XTZHMintRecord {
mint_id: mint_id.to_string(),
asset_dna_hash: asset_dna_hash.to_string(),
asset_type,
amount,
owner_did: owner_did.to_string(),
gold_reserve_anchor_hash: gold_reserve_anchor_hash.to_string(),
health_factor: 150, // 初始健康因子150%
timestamp,
status: MintStatus::Active,
};
// 增加所有者余额
let owner_balance = self.balance_of(owner_did);
let mut new_owner_balance = owner_balance.clone();
new_owner_balance.available += amount;
self.balances
.insert(owner_did.to_string(), new_owner_balance);
// 更新总供应量和流通供应量
self.token.total_supply += amount;
self.token.circulating_supply += amount;
// 记录铸造
self.mint_records
.insert(mint_id.to_string(), mint_record);
Ok(())
}
/// 销毁XTZH内部方法由赎回/清算协议调用)
pub fn burn(&mut self, address: &str, amount: u128) -> Result<(), String> {
// 检查余额
let balance = self.balance_of(address);
if balance.available < amount {
return Err("Insufficient balance to burn".to_string());
}
// 扣除余额
let mut new_balance = balance.clone();
new_balance.available -= amount;
self.balances.insert(address.to_string(), new_balance);
// 更新总供应量和流通供应量
self.token.total_supply -= amount;
self.token.circulating_supply -= amount;
Ok(())
}
/// 锁定XTZH用于铸造抵押
pub fn lock(&mut self, address: &str, amount: u128) -> Result<(), String> {
let balance = self.balance_of(address);
if balance.available < amount {
return Err("Insufficient available balance to lock".to_string());
}
let mut new_balance = balance.clone();
new_balance.available -= amount;
new_balance.locked += amount;
self.balances.insert(address.to_string(), new_balance);
Ok(())
}
/// 解锁XTZH
pub fn unlock(&mut self, address: &str, amount: u128) -> Result<(), String> {
let balance = self.balance_of(address);
if balance.locked < amount {
return Err("Insufficient locked balance to unlock".to_string());
}
let mut new_balance = balance.clone();
new_balance.locked -= amount;
new_balance.available += amount;
self.balances.insert(address.to_string(), new_balance);
Ok(())
}
/// 冻结XTZH用于清算
pub fn freeze(&mut self, address: &str, amount: u128) -> Result<(), String> {
let balance = self.balance_of(address);
if balance.available < amount {
return Err("Insufficient available balance to freeze".to_string());
}
let mut new_balance = balance.clone();
new_balance.available -= amount;
new_balance.frozen += amount;
self.balances.insert(address.to_string(), new_balance);
Ok(())
}
/// 解冻XTZH
pub fn unfreeze(&mut self, address: &str, amount: u128) -> Result<(), String> {
let balance = self.balance_of(address);
if balance.frozen < amount {
return Err("Insufficient frozen balance to unfreeze".to_string());
}
let mut new_balance = balance.clone();
new_balance.frozen -= amount;
new_balance.available += amount;
self.balances.insert(address.to_string(), new_balance);
Ok(())
}
/// 更新健康因子
pub fn update_health_factor(
&mut self,
mint_id: &str,
new_health_factor: u16,
) -> Result<(), String> {
let mint_record = self
.mint_records
.get_mut(mint_id)
.ok_or("Mint record not found")?;
mint_record.health_factor = new_health_factor;
// 更新状态
if new_health_factor < 100 {
mint_record.status = MintStatus::Liquidating;
} else if new_health_factor < 110 {
mint_record.status = MintStatus::Warning;
} else {
mint_record.status = MintStatus::Active;
}
Ok(())
}
/// 更新黄金储备覆盖率
pub fn update_gold_coverage_ratio(&mut self, new_gcr: u16) -> Result<(), String> {
if new_gcr < self.token.min_gold_coverage_ratio {
return Err(format!(
"GCR {} is below minimum {}",
new_gcr, self.token.min_gold_coverage_ratio
));
}
self.token.gold_coverage_ratio = new_gcr;
Ok(())
}
/// 获取所有预警铸造记录
pub fn get_warning_mints(&self) -> Vec<&XTZHMintRecord> {
self.mint_records
.values()
.filter(|record| record.status == MintStatus::Warning)
.collect()
}
/// 获取所有清算中铸造记录
pub fn get_liquidating_mints(&self) -> Vec<&XTZHMintRecord> {
self.mint_records
.values()
.filter(|record| record.status == MintStatus::Liquidating)
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_xtzh_protocol_creation() {
let protocol = XTZHProtocol::new();
assert_eq!(protocol.token.symbol, "XTZH");
assert_eq!(protocol.token.decimals, 8);
assert_eq!(protocol.token.total_supply, 0);
assert_eq!(protocol.token.gold_coverage_ratio, 125);
}
#[test]
fn test_xtzh_mint() {
let mut protocol = XTZHProtocol::new();
let result = protocol.mint(
"mint_001",
"asset_dna_hash_001",
AssetType::RWA,
1000_0000_0000, // 1000 XTZH
"owner_did_001",
"gold_reserve_anchor_001",
1700000000,
);
assert!(result.is_ok());
assert_eq!(protocol.token.total_supply, 1000_0000_0000);
assert_eq!(protocol.balance_of("owner_did_001").available, 1000_0000_0000);
}
#[test]
fn test_xtzh_transfer() {
let mut protocol = XTZHProtocol::new();
// 先铸造一些XTZH
protocol
.mint(
"mint_001",
"asset_dna_hash_001",
AssetType::RWA,
1000_0000_0000,
"alice",
"gold_reserve_anchor_001",
1700000000,
)
.expect("mainnet: handle error");
// 转账
let result = protocol.transfer("alice", "bob", 300_0000_0000, 1700000001);
assert!(result.is_ok());
assert_eq!(protocol.balance_of("alice").available, 700_0000_0000);
assert_eq!(protocol.balance_of("bob").available, 300_0000_0000);
}
#[test]
fn test_xtzh_burn() {
let mut protocol = XTZHProtocol::new();
// 先铸造
protocol
.mint(
"mint_001",
"asset_dna_hash_001",
AssetType::RWA,
1000_0000_0000,
"alice",
"gold_reserve_anchor_001",
1700000000,
)
.expect("mainnet: handle error");
// 销毁
let result = protocol.burn("alice", 300_0000_0000);
assert!(result.is_ok());
assert_eq!(protocol.balance_of("alice").available, 700_0000_0000);
assert_eq!(protocol.token.total_supply, 700_0000_0000);
}
#[test]
fn test_xtzh_lock_unlock() {
let mut protocol = XTZHProtocol::new();
// 先铸造
protocol
.mint(
"mint_001",
"asset_dna_hash_001",
AssetType::RWA,
1000_0000_0000,
"alice",
"gold_reserve_anchor_001",
1700000000,
)
.expect("mainnet: handle error");
// 锁定
protocol.lock("alice", 300_0000_0000).expect("mainnet: handle error");
let balance = protocol.balance_of("alice");
assert_eq!(balance.available, 700_0000_0000);
assert_eq!(balance.locked, 300_0000_0000);
// 解锁
protocol.unlock("alice", 100_0000_0000).expect("mainnet: handle error");
let balance = protocol.balance_of("alice");
assert_eq!(balance.available, 800_0000_0000);
assert_eq!(balance.locked, 200_0000_0000);
}
#[test]
fn test_health_factor_update() {
let mut protocol = XTZHProtocol::new();
// 先铸造
protocol
.mint(
"mint_001",
"asset_dna_hash_001",
AssetType::RWA,
1000_0000_0000,
"alice",
"gold_reserve_anchor_001",
1700000000,
)
.expect("mainnet: handle error");
// 更新健康因子到预警状态
protocol.update_health_factor("mint_001", 105).expect("mainnet: handle error");
let record = protocol.mint_records.get("mint_001").expect("mainnet: handle error");
assert_eq!(record.health_factor, 105);
assert_eq!(record.status, MintStatus::Warning);
// 更新健康因子到清算状态
protocol.update_health_factor("mint_001", 95).expect("mainnet: handle error");
let record = protocol.mint_records.get("mint_001").expect("mainnet: handle error");
assert_eq!(record.health_factor, 95);
assert_eq!(record.status, MintStatus::Liquidating);
}
#[test]
fn test_gold_coverage_ratio() {
let mut protocol = XTZHProtocol::new();
// 更新GCR
protocol.update_gold_coverage_ratio(110).expect("mainnet: handle error");
assert_eq!(protocol.token.gold_coverage_ratio, 110);
// 尝试设置低于最低值的GCR
let result = protocol.update_gold_coverage_ratio(95);
assert!(result.is_err());
}
}