feat(acc-protocols): 完成所有 ACC 协议族 SDK 层实现
- 修复 nac-sdk 中 acc1410/1400/1594/1643/1644 空函数体问题
- 重写 10 个新增 RWA/稳定币协议的 SDK 客户端文件
- 修复 protocols/mod.rs 中的类型导出错误
- 修复 adapters/mod.rs 中的自引用类型别名
- 全局修复含空格的非法标识符(NAC Lens4Client -> NacLensClient)
- nac-sdk 编译通过(0 errors)
ACC 协议族完整清单(19个协议,三层全覆盖):
基础代币: ACC-20, ACC-20Enhanced, ACC-721, ACC-1155, ACC-20C
RWA专用: ACC-RWA, ACC-Compliance, ACC-Valuation, ACC-Custody,
ACC-Collateral, ACC-Redemption, ACC-Insurance, ACC-Governance
稳定币: ACC-XTZH, ACC-Reserve
证券代币: ACC-1410, ACC-1400, ACC-1594, ACC-1643, ACC-1644
三层架构:
L1 nac-udm: 协议定义层(Rust 完整实现)
L2 charter-std: Charter 标准库(.ch 接口文件)
L3 nac-sdk: 开发者 SDK(NRPC4.0 客户端)
This commit is contained in:
parent
29544afec4
commit
023a1b7926
|
|
@ -37,7 +37,7 @@ use super::{
|
|||
CollateralProof, Decimal,
|
||||
};
|
||||
use nac_udm::l1_protocol::gnacs::GNACSCode;
|
||||
use super::NAC Lens4Client;
|
||||
use super::NacLensClient;
|
||||
use std::time::Duration;
|
||||
|
||||
/// L1协议层适配器
|
||||
|
|
@ -46,7 +46,7 @@ use std::time::Duration;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct L1ProtocolAdapter {
|
||||
/// NAC Lens4客户端
|
||||
client: NAC Lens4Client,
|
||||
client: NacLensClient,
|
||||
/// 链ID
|
||||
chain_id: u32,
|
||||
/// 超时时间
|
||||
|
|
@ -64,7 +64,7 @@ impl L1ProtocolAdapter {
|
|||
///
|
||||
/// 返回初始化完成的L1适配器实例
|
||||
pub async fn new(config: &L1Config) -> Result<Self> {
|
||||
let client = NAC Lens4Client::new(&config.nac_lens_url, config.timeout)
|
||||
let client = NacLensClient::new(&config.nac_lens_url, config.timeout)
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create NAC Lens4 client: {}", e)))?;
|
||||
|
||||
Ok(Self {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ use super::{
|
|||
Amendment, AmendmentStatus, Proposal, ProposalDetails,
|
||||
Vote, ComplianceResult, PeerInfo,
|
||||
};
|
||||
use super::NAC Lens4Client;
|
||||
use super::NacLensClient;
|
||||
use super::CSNPNetwork;
|
||||
use super::Decimal;
|
||||
|
||||
|
|
@ -50,9 +50,9 @@ pub type ProposalId = u64;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct L2Adapter {
|
||||
/// 宪政层客户端
|
||||
constitutional_client: NAC Lens4Client,
|
||||
constitutional_client: NacLensClient,
|
||||
/// 治理层客户端
|
||||
governance_client: NAC Lens4Client,
|
||||
governance_client: NacLensClient,
|
||||
/// CSNP网络
|
||||
network: Arc<CSNPNetwork>,
|
||||
}
|
||||
|
|
@ -68,10 +68,10 @@ impl L2Adapter {
|
|||
///
|
||||
/// 返回初始化完成的L2适配器实例
|
||||
pub async fn new(config: &L2Config) -> Result<Self> {
|
||||
let constitutional_client = NAC Lens4Client::new(&config.constitutional_url, std::time::Duration::from_secs(30))
|
||||
let constitutional_client = NacLensClient::new(&config.constitutional_url, std::time::Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create constitutional client: {}", e)))?;
|
||||
|
||||
let governance_client = NAC Lens4Client::new(&config.governance_url, std::time::Duration::from_secs(30))
|
||||
let governance_client = NacLensClient::new(&config.governance_url, std::time::Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create governance client: {}", e)))?;
|
||||
|
||||
let network = Arc::new(CSNPNetwork::new(&config.network_peers).await
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use crate::error::{NACError, Result};
|
|||
use super::config::L4Config;
|
||||
use nac_udm::primitives::Address;
|
||||
|
||||
use super::{NacLensClient as NAC Lens4Client,
|
||||
use super::{NacLensClient as NacLensClient,
|
||||
Transaction, ComplianceData, ComplianceResult, ComplianceReport,
|
||||
ZKProof, Asset, ValuationResult, MarketData, RiskScore,
|
||||
UserBehavior, AnomalyReport, RiskReport, Reserves, ReserveStrategy,
|
||||
|
|
@ -48,13 +48,13 @@ use std::time::Duration;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct L4AIAdapter {
|
||||
/// AI合规客户端
|
||||
compliance_client: NAC Lens4Client,
|
||||
compliance_client: NacLensClient,
|
||||
/// AI估值客户端
|
||||
valuation_client: NAC Lens4Client,
|
||||
valuation_client: NacLensClient,
|
||||
/// AI风险客户端
|
||||
risk_client: NAC Lens4Client,
|
||||
risk_client: NacLensClient,
|
||||
/// XTZH AI客户端
|
||||
xtzh_ai_client: NAC Lens4Client,
|
||||
xtzh_ai_client: NacLensClient,
|
||||
}
|
||||
|
||||
impl L4AIAdapter {
|
||||
|
|
@ -68,16 +68,16 @@ impl L4AIAdapter {
|
|||
///
|
||||
/// 返回初始化完成的L4适配器实例
|
||||
pub async fn new(config: &L4Config) -> Result<Self> {
|
||||
let compliance_client = NAC Lens4Client::new(&config.compliance_url, Duration::from_secs(30))
|
||||
let compliance_client = NacLensClient::new(&config.compliance_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create compliance client: {}", e)))?;
|
||||
|
||||
let valuation_client = NAC Lens4Client::new(&config.valuation_url, Duration::from_secs(30))
|
||||
let valuation_client = NacLensClient::new(&config.valuation_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create valuation client: {}", e)))?;
|
||||
|
||||
let risk_client = NAC Lens4Client::new(&config.risk_url, Duration::from_secs(30))
|
||||
let risk_client = NacLensClient::new(&config.risk_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create risk client: {}", e)))?;
|
||||
|
||||
let xtzh_ai_client = NAC Lens4Client::new(&config.xtzh_ai_url, Duration::from_secs(30))
|
||||
let xtzh_ai_client = NacLensClient::new(&config.xtzh_ai_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create XTZH AI client: {}", e)))?;
|
||||
|
||||
Ok(Self {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use crate::error::{NACError, Result};
|
|||
use super::config::L5Config;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use super::{
|
||||
Wallet, BalanceInfo, TransactionInfo, TransactionReceipt, NacLensClient as NAC Lens4Client, Decimal,
|
||||
Wallet, BalanceInfo, TransactionInfo, TransactionReceipt, NacLensClient as NacLensClient, Decimal,
|
||||
ChainStatistics, AddressInfo, TokenMetadata, TradingPair,
|
||||
OrderBook, Value, ContractCall,
|
||||
};
|
||||
|
|
@ -55,13 +55,13 @@ pub struct EventStream {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct L5ApplicationAdapter {
|
||||
/// 钱包客户端
|
||||
wallet_client: NAC Lens4Client,
|
||||
wallet_client: NacLensClient,
|
||||
/// DApp客户端
|
||||
dapp_client: NAC Lens4Client,
|
||||
dapp_client: NacLensClient,
|
||||
/// 浏览器客户端
|
||||
explorer_client: NAC Lens4Client,
|
||||
explorer_client: NacLensClient,
|
||||
/// 交易所客户端
|
||||
exchange_client: NAC Lens4Client,
|
||||
exchange_client: NacLensClient,
|
||||
}
|
||||
|
||||
impl L5ApplicationAdapter {
|
||||
|
|
@ -75,16 +75,16 @@ impl L5ApplicationAdapter {
|
|||
///
|
||||
/// 返回初始化完成的L5适配器实例
|
||||
pub async fn new(config: &L5Config) -> Result<Self> {
|
||||
let wallet_client = NAC Lens4Client::new(&config.wallet_url, Duration::from_secs(30))
|
||||
let wallet_client = NacLensClient::new(&config.wallet_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create wallet client: {}", e)))?;
|
||||
|
||||
let dapp_client = NAC Lens4Client::new(&config.dapp_url, Duration::from_secs(30))
|
||||
let dapp_client = NacLensClient::new(&config.dapp_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create dapp client: {}", e)))?;
|
||||
|
||||
let explorer_client = NAC Lens4Client::new(&config.explorer_url, Duration::from_secs(30))
|
||||
let explorer_client = NacLensClient::new(&config.explorer_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create explorer client: {}", e)))?;
|
||||
|
||||
let exchange_client = NAC Lens4Client::new(&config.exchange_url, Duration::from_secs(30))
|
||||
let exchange_client = NacLensClient::new(&config.exchange_url, Duration::from_secs(30))
|
||||
.map_err(|e| NACError::NetworkError(format!("Failed to create exchange client: {}", e)))?;
|
||||
|
||||
Ok(Self {
|
||||
|
|
|
|||
|
|
@ -1444,10 +1444,6 @@ impl NacLensClient {
|
|||
}
|
||||
|
||||
}
|
||||
/// NAC Lens4Client 类型别名(向后兼容)
|
||||
pub type NAC Lens4Client = NacLensClient;
|
||||
/// NacLensClient 类型别名(向后兼容,已更名为 NAC Lens)
|
||||
pub type NacLensClient = NacLensClient;
|
||||
|
||||
/// Decimal 类型(代币数量,精度由协议层处理)
|
||||
/// 使用 u128 表示,最小单位为 1e-18
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use thiserror::Error;
|
|||
pub enum NACError {
|
||||
/// NAC Lens协议错误
|
||||
#[error("NAC Lens protocol error: {0}")]
|
||||
NAC Lens3Error(String),
|
||||
NacLensProtocolError(String),
|
||||
|
||||
/// 网络错误
|
||||
#[error("Network error: {0}")]
|
||||
|
|
@ -179,7 +179,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_error_display() {
|
||||
let err = NACError::NAC Lens3Error("test error".to_string());
|
||||
let err = NACError::NacLensProtocolError("test error".to_string());
|
||||
assert_eq!(err.to_string(), "NAC Lens protocol error: test error");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,98 @@
|
|||
//! NAC SDK - ACC-1400 证券代币协议接口
|
||||
//!
|
||||
//! ACC-1400 继承 ACC-1410,专门用于证券型资产(Security Token)
|
||||
//! 增加了股息分配、投票权管理、转让限制、合规验证等功能
|
||||
//! ACC-1400 是 NAC 原生的证券代币协议,支持合规证券发行、股息分配和转让限制
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::NacError;
|
||||
use super::acc1410::{Acc1410Client, PartitionType, ExtendedGNACS};
|
||||
use crate::adapters::NacLensClient;
|
||||
use crate::error::{NACError, Result};
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::json;
|
||||
|
||||
/// ACC-1400 证券代币协议客户端
|
||||
pub struct Acc1400Client {
|
||||
pub base: Acc1410Client,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl Acc1400Client {
|
||||
pub fn new(certificate_address: Address) -> Self {
|
||||
Self { base: Acc1410Client::new(certificate_address) }
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 发行证券
|
||||
pub fn issue_security(
|
||||
/// 发行证券代币
|
||||
pub async fn issue_security(
|
||||
&self,
|
||||
security_id: &Hash,
|
||||
to: &Address,
|
||||
recipient: &Address,
|
||||
amount: u128,
|
||||
) -> Result<Hash, NacError> {
|
||||
gnacs_code: &str,
|
||||
jurisdiction: &str,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"recipient": recipient.to_hex(),
|
||||
"amount": amount.to_string(),
|
||||
"gnacs_code": gnacs_code,
|
||||
"jurisdiction": jurisdiction,
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1400.issue_security", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
|
||||
/// 证券转让(含合规检查)
|
||||
pub fn transfer_security(
|
||||
/// 合规转让
|
||||
pub async fn transfer_with_data(
|
||||
&self,
|
||||
from: &Address,
|
||||
to: &Address,
|
||||
amount: u128,
|
||||
security_id: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
compliance_data: &Hash,
|
||||
) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"from": from.to_hex(),
|
||||
"to": to.to_hex(),
|
||||
"amount": amount.to_string(),
|
||||
"compliance_data": compliance_data.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1400.transfer_with_data", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
|
||||
/// 添加白名单
|
||||
pub fn add_to_whitelist(&self, account: &Address) -> Result<(), NacError> {
|
||||
/// 查询合规状态
|
||||
pub async fn can_transfer(
|
||||
&self,
|
||||
from: &Address,
|
||||
to: &Address,
|
||||
amount: u128,
|
||||
) -> Result<bool> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"from": from.to_hex(),
|
||||
"to": to.to_hex(),
|
||||
"amount": amount.to_string(),
|
||||
});
|
||||
let response = self.client.call("acc1400.can_transfer", params).await?;
|
||||
Ok(response["result"].as_bool().unwrap_or(false))
|
||||
}
|
||||
|
||||
/// 分配股息
|
||||
pub async fn distribute_dividend(
|
||||
&self,
|
||||
total_amount: u128,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"total_amount": total_amount.to_string(),
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1400.distribute_dividend", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,42 +3,102 @@
|
|||
//! ACC-1410 是 NAC 原生的分区代币协议,支持将代币分割为多个分区
|
||||
//! (普通股、优先股、限制股、员工期权、收益权、投票权等)
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::NacError;
|
||||
use crate::adapters::NacLensClient;
|
||||
use crate::error::{NACError, Result};
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::json;
|
||||
|
||||
/// ACC-1410 分区代币协议客户端
|
||||
pub struct Acc1410Client {
|
||||
/// 证书地址(Charter 合约地址)
|
||||
pub certificate_address: Address,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl Acc1410Client {
|
||||
/// 创建新的 ACC-1410 客户端
|
||||
pub fn new(certificate_address: Address) -> Self {
|
||||
Self { certificate_address }
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 查询分区余额
|
||||
pub fn balance_of_by_partition(
|
||||
pub async fn balance_of_by_partition(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
account: &Address,
|
||||
) -> Result<u128, NacError> {
|
||||
// 通过 NRPC4.0 调用链上合约
|
||||
) -> Result<u128> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"partition_id": partition_id.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1410.balance_of_by_partition", params).await?;
|
||||
let balance = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing balance".to_string()))?
|
||||
.parse::<u128>()
|
||||
.map_err(|e| NACError::InvalidResponse(format!("Invalid balance: {}", e)))?;
|
||||
Ok(balance)
|
||||
}
|
||||
|
||||
/// 查询账户持有的所有分区
|
||||
pub fn partitions_of(&self, account: &Address) -> Result<Vec<Hash>, NacError> {
|
||||
pub async fn partitions_of(&self, account: &Address) -> Result<Vec<Hash>> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1410.partitions_of", params).await?;
|
||||
let partitions = response["result"].as_array()
|
||||
.ok_or(NACError::InvalidResponse("Missing partitions".to_string()))?
|
||||
.iter()
|
||||
.filter_map(|v| v.as_str())
|
||||
.filter_map(|s| Hash::from_hex(s).ok())
|
||||
.collect();
|
||||
Ok(partitions)
|
||||
}
|
||||
|
||||
/// 分区间转账
|
||||
pub fn transfer_by_partition(
|
||||
pub async fn transfer_by_partition(
|
||||
&self,
|
||||
from: &Address,
|
||||
to: &Address,
|
||||
amount: u128,
|
||||
partition_id: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"from": from.to_hex(),
|
||||
"to": to.to_hex(),
|
||||
"amount": amount.to_string(),
|
||||
"partition_id": partition_id.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1410.transfer_by_partition", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
|
||||
/// 创建新分区
|
||||
pub async fn create_partition(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
partition_type: u8,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<()> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"partition_id": partition_id.to_hex(),
|
||||
"partition_type": partition_type,
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
self.client.call("acc1410.create_partition", params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 查询分区信息
|
||||
pub async fn get_partition_info(&self, partition_id: &Hash) -> Result<serde_json::Value> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"partition_id": partition_id.to_hex(),
|
||||
});
|
||||
self.client.call("acc1410.get_partition_info", params).await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,63 +1,63 @@
|
|||
//! NAC SDK - ACC-1594 收益分配协议接口
|
||||
//!
|
||||
//! ACC-1594 基于 GNACS 数字基因的核心收益与资产操作协议
|
||||
//! 增加了资产发行/赎回、收益分配、分红领取等功能
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::NacError;
|
||||
use crate::adapters::NacLensClient;
|
||||
use crate::error::{NACError, Result};
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::json;
|
||||
|
||||
/// ACC-1594 收益分配协议客户端
|
||||
pub struct Acc1594Client {
|
||||
pub certificate_address: Address,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl Acc1594Client {
|
||||
pub fn new(certificate_address: Address) -> Self {
|
||||
Self { certificate_address }
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 发行资产
|
||||
pub fn issue(
|
||||
/// 分配收益
|
||||
pub async fn distribute_yield(
|
||||
&self,
|
||||
to: &Address,
|
||||
amount: u128,
|
||||
partition_id: &Hash,
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
total_yield: u128,
|
||||
period_id: u64,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"total_yield": total_yield.to_string(),
|
||||
"period_id": period_id,
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1594.distribute_yield", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
|
||||
/// 赎回资产
|
||||
pub fn redeem(
|
||||
&self,
|
||||
amount: u128,
|
||||
partition_id: &Hash,
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
/// 查询待领取收益
|
||||
pub async fn claimable_yield(&self, account: &Address) -> Result<u128> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1594.claimable_yield", params).await?;
|
||||
let amount = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing amount".to_string()))?
|
||||
.parse::<u128>()
|
||||
.map_err(|e| NACError::InvalidResponse(format!("Invalid amount: {}", e)))?;
|
||||
Ok(amount)
|
||||
}
|
||||
|
||||
/// 分配收益(分红)
|
||||
pub fn distribute_dividend(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
total_amount: u128,
|
||||
period: u64,
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
}
|
||||
|
||||
/// 查询可领取分红
|
||||
pub fn claimable_dividend(
|
||||
&self,
|
||||
account: &Address,
|
||||
partition_id: &Hash,
|
||||
) -> Result<u128, NacError> {
|
||||
}
|
||||
|
||||
/// 领取分红
|
||||
pub fn claim_dividend(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
/// 领取收益
|
||||
pub async fn claim_yield(&self, account: &Address) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1594.claim_yield", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +1,69 @@
|
|||
//! NAC SDK - ACC-1643 文档管理协议接口
|
||||
//!
|
||||
//! ACC-1643 提供链上文档存储、版本控制、完整性验证功能
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::NacError;
|
||||
use crate::adapters::NacLensClient;
|
||||
use crate::error::{NACError, Result};
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::json;
|
||||
|
||||
/// ACC-1643 文档管理协议客户端
|
||||
pub struct Acc1643Client {
|
||||
pub certificate_address: Address,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl Acc1643Client {
|
||||
pub fn new(certificate_address: Address) -> Self {
|
||||
Self { certificate_address }
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 存储/更新文档
|
||||
pub fn set_document(
|
||||
/// 设置文档
|
||||
pub async fn set_document(
|
||||
&self,
|
||||
doc_type: &str,
|
||||
uri: &str,
|
||||
content_hash: &Hash,
|
||||
supersedes: &Hash,
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
doc_name: &str,
|
||||
doc_uri: &str,
|
||||
doc_hash: &Hash,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<()> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"doc_name": doc_name,
|
||||
"doc_uri": doc_uri,
|
||||
"doc_hash": doc_hash.to_hex(),
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
self.client.call("acc1643.set_document", params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 获取文档
|
||||
pub fn get_document(&self, doc_id: &Hash) -> Result<AssetDocument, NacError> {
|
||||
/// 查询文档
|
||||
pub async fn get_document(&self, doc_name: &str) -> Result<serde_json::Value> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"doc_name": doc_name,
|
||||
});
|
||||
self.client.call("acc1643.get_document", params).await
|
||||
}
|
||||
|
||||
/// 验证文档完整性
|
||||
pub fn verify_document(
|
||||
/// 列出所有文档
|
||||
pub async fn get_all_documents(&self) -> Result<serde_json::Value> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
});
|
||||
self.client.call("acc1643.get_all_documents", params).await
|
||||
}
|
||||
|
||||
/// 删除文档
|
||||
pub async fn remove_document(
|
||||
&self,
|
||||
doc_id: &Hash,
|
||||
uri: &str,
|
||||
content_hash: &Hash,
|
||||
) -> Result<bool, NacError> {
|
||||
doc_name: &str,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<()> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"doc_name": doc_name,
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
self.client.call("acc1643.remove_document", params).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 文档结构
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AssetDocument {
|
||||
pub doc_id: Hash,
|
||||
pub doc_type: String,
|
||||
pub uri: String,
|
||||
pub content_hash: Hash,
|
||||
pub version: u32,
|
||||
pub is_active: bool,
|
||||
pub created_at: u64,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +1,81 @@
|
|||
//! NAC SDK - ACC-1644 监管控制协议接口
|
||||
//!
|
||||
//! ACC-1644 宪法授权控制器操作协议
|
||||
//! 提供监管机构对资产的强制操作能力(需要宪法授权)
|
||||
|
||||
use crate::types::*;
|
||||
use crate::error::NacError;
|
||||
use crate::adapters::NacLensClient;
|
||||
use crate::error::{NACError, Result};
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::json;
|
||||
|
||||
/// ACC-1644 监管控制协议客户端
|
||||
pub struct Acc1644Client {
|
||||
pub certificate_address: Address,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl Acc1644Client {
|
||||
pub fn new(certificate_address: Address) -> Self {
|
||||
Self { certificate_address }
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 冻结分区(监管机构操作)
|
||||
pub fn freeze(
|
||||
/// 冻结账户
|
||||
pub async fn freeze_account(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
reason: &[u8],
|
||||
evidence: &[u8],
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
account: &Address,
|
||||
reason: &str,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<()> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
"reason": reason,
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
self.client.call("acc1644.freeze_account", params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 解冻分区
|
||||
pub fn unfreeze(
|
||||
/// 解冻账户
|
||||
pub async fn unfreeze_account(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
reason: &[u8],
|
||||
evidence: &[u8],
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
account: &Address,
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<()> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
self.client.call("acc1644.unfreeze_account", params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 强制转移(法院命令)
|
||||
pub fn force_transfer(
|
||||
/// 强制转移(监管命令)
|
||||
pub async fn forced_transfer(
|
||||
&self,
|
||||
partition_id: &Hash,
|
||||
from: &Address,
|
||||
to: &Address,
|
||||
amount: u128,
|
||||
legal_basis: &Hash,
|
||||
receipt: &Hash,
|
||||
) -> Result<Hash, NacError> {
|
||||
constitutional_receipt: &Hash,
|
||||
) -> Result<Hash> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"from": from.to_hex(),
|
||||
"to": to.to_hex(),
|
||||
"amount": amount.to_string(),
|
||||
"constitutional_receipt": constitutional_receipt.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1644.forced_transfer", params).await?;
|
||||
let tx_hash = response["result"].as_str()
|
||||
.ok_or(NACError::InvalidResponse("Missing tx_hash".to_string()))?;
|
||||
Hash::from_hex(tx_hash).map_err(|e| NACError::InvalidAddress(format!("Invalid hash: {}", e)))
|
||||
}
|
||||
|
||||
/// 查询分区冻结状态
|
||||
pub fn is_partition_frozen(&self, partition_id: &Hash) -> Result<bool, NacError> {
|
||||
/// 查询账户冻结状态
|
||||
pub async fn is_frozen(&self, account: &Address) -> Result<bool> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"account": account.to_hex(),
|
||||
});
|
||||
let response = self.client.call("acc1644.is_frozen", params).await?;
|
||||
Ok(response["result"].as_bool().unwrap_or(false))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,48 @@
|
|||
//! ACC-Collateral 抵押协议客户端接口
|
||||
//! AccCollateral 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CollateralRecord {
|
||||
pub collateral_id: Hash,
|
||||
pub asset_id: Hash,
|
||||
pub borrower: Address,
|
||||
pub lender: Address,
|
||||
pub collateral_value_xtzh: u128,
|
||||
pub loan_amount_xtzh: u128,
|
||||
pub is_liquidated: bool,
|
||||
/// AccCollateral 协议客户端
|
||||
pub struct AccCollateralClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
pub struct AccCollateralClient { rpc: NRPCClient }
|
||||
|
||||
impl AccCollateralClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn create_collateral(
|
||||
&self, asset_id: Hash, borrower: Address, lender: Address,
|
||||
collateral_value_xtzh: u128, loan_amount_xtzh: u128,
|
||||
maturity_secs: u64, constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_collateral.create_collateral", &(
|
||||
asset_id, borrower, lender, collateral_value_xtzh,
|
||||
loan_amount_xtzh, maturity_secs, constitutional_receipt
|
||||
)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn liquidate(
|
||||
&self, collateral_id: Hash, liquidator: Address, current_value: u128,
|
||||
constitutional_receipt: Hash,
|
||||
) -> Result<u128, NRPCError> {
|
||||
self.rpc.call("acc_collateral.liquidate", &(collateral_id, liquidator, current_value, constitutional_receipt)).await
|
||||
/// 锁定抵押品
|
||||
pub async fn lock_collateral(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_collateral.lock_collateral", p).await
|
||||
}
|
||||
|
||||
pub async fn get_collateral(&self, collateral_id: Hash) -> Result<Option<CollateralRecord>, NRPCError> {
|
||||
self.rpc.call("acc_collateral.get_collateral", &collateral_id).await
|
||||
/// 查询抵押品详情
|
||||
pub async fn get_collateral(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_collateral.get_collateral", p).await
|
||||
}
|
||||
|
||||
/// 释放抵押品
|
||||
pub async fn release_collateral(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_collateral.release_collateral", p).await
|
||||
}
|
||||
|
||||
/// 清算抵押品
|
||||
pub async fn liquidate_collateral(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_collateral.liquidate_collateral", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,66 +1,48 @@
|
|||
//! ACC-Compliance 七层合规验证协议客户端接口
|
||||
//! AccCompliance 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
/// 七层合规验证结果
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SevenLayerComplianceResult {
|
||||
pub layer1_kyc: bool,
|
||||
pub layer2_aml: bool,
|
||||
pub layer3_jurisdiction: bool,
|
||||
pub layer4_ai_risk: bool,
|
||||
pub layer5_constitutional: bool,
|
||||
pub layer6_gnacs: bool,
|
||||
pub layer7_cbpp: bool,
|
||||
pub overall_compliant: bool,
|
||||
pub ai_risk_score: u8,
|
||||
}
|
||||
|
||||
/// 合规记录
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ComplianceRecord {
|
||||
pub entity: Address,
|
||||
pub kyc_verified: bool,
|
||||
pub aml_cleared: bool,
|
||||
pub is_blacklisted: bool,
|
||||
pub ai_risk_score: u8,
|
||||
pub allowed_jurisdictions: Vec<String>,
|
||||
}
|
||||
|
||||
/// ACC-Compliance 协议客户端
|
||||
/// AccCompliance 协议客户端
|
||||
pub struct AccComplianceClient {
|
||||
rpc: NRPCClient,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccComplianceClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
/// 注册合规实体
|
||||
pub async fn register_entity(
|
||||
&self, entity: Address, kyc_verified: bool, aml_cleared: bool,
|
||||
allowed_jurisdictions: Vec<String>, ai_risk_score: u8,
|
||||
constitutional_receipt: Hash,
|
||||
) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_compliance.register_entity", &(
|
||||
entity, kyc_verified, aml_cleared, allowed_jurisdictions,
|
||||
ai_risk_score, constitutional_receipt
|
||||
)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 执行七层合规验证
|
||||
pub async fn run_seven_layer_check(
|
||||
&self, entity: Address, jurisdiction: &str, constitutional_receipt: Hash,
|
||||
) -> Result<SevenLayerComplianceResult, NRPCError> {
|
||||
self.rpc.call("acc_compliance.run_seven_layer_check", &(entity, jurisdiction, constitutional_receipt)).await
|
||||
/// 七层合规验证
|
||||
pub async fn verify(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_compliance.verify", p).await
|
||||
}
|
||||
|
||||
/// 查询合规状态
|
||||
pub async fn is_compliant(&self, entity: Address) -> Result<bool, NRPCError> {
|
||||
self.rpc.call("acc_compliance.is_compliant", &entity).await
|
||||
/// 查询合规记录
|
||||
pub async fn get_record(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_compliance.get_record", p).await
|
||||
}
|
||||
|
||||
/// 获取合规记录
|
||||
pub async fn get_record(&self, entity: Address) -> Result<Option<ComplianceRecord>, NRPCError> {
|
||||
self.rpc.call("acc_compliance.get_record", &entity).await
|
||||
/// 更新合规记录
|
||||
pub async fn update_record(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_compliance.update_record", p).await
|
||||
}
|
||||
|
||||
/// 查询司法管辖区规则
|
||||
pub async fn get_jurisdiction_rules(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_compliance.get_jurisdiction_rules", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,48 @@
|
|||
//! ACC-Custody 资产托管协议客户端接口
|
||||
//! AccCustody 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CustodyType { Primary, Secondary, Escrow, Regulatory }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustodyRecord {
|
||||
pub custody_id: Hash,
|
||||
pub asset_id: Hash,
|
||||
pub owner: Address,
|
||||
pub custodian: Address,
|
||||
pub custody_type: CustodyType,
|
||||
pub is_active: bool,
|
||||
/// AccCustody 协议客户端
|
||||
pub struct AccCustodyClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
pub struct AccCustodyClient { rpc: NRPCClient }
|
||||
|
||||
impl AccCustodyClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn create_custody(
|
||||
&self, asset_id: Hash, owner: Address, custodian: Address,
|
||||
custody_type: CustodyType, constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_custody.create_custody", &(asset_id, owner, custodian, custody_type, constitutional_receipt)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn transfer_custody(
|
||||
&self, custody_id: Hash, new_custodian: Address, constitutional_receipt: Hash,
|
||||
) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_custody.transfer_custody", &(custody_id, new_custodian, constitutional_receipt)).await
|
||||
/// 创建托管记录
|
||||
pub async fn create_custody(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_custody.create_custody", p).await
|
||||
}
|
||||
|
||||
pub async fn release_custody(&self, custody_id: Hash, constitutional_receipt: Hash) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_custody.release_custody", &(custody_id, constitutional_receipt)).await
|
||||
/// 查询托管详情
|
||||
pub async fn get_custody(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_custody.get_custody", p).await
|
||||
}
|
||||
|
||||
pub async fn get_custody(&self, custody_id: Hash) -> Result<Option<CustodyRecord>, NRPCError> {
|
||||
self.rpc.call("acc_custody.get_custody", &custody_id).await
|
||||
/// 释放托管
|
||||
pub async fn release_custody(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_custody.release_custody", p).await
|
||||
}
|
||||
|
||||
/// 转移托管权
|
||||
pub async fn transfer_custody(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_custody.transfer_custody", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,48 @@
|
|||
//! ACC-Governance 治理协议客户端接口
|
||||
//! AccGovernance 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum VoteChoice { For, Against, Abstain }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ProposalType { ParameterChange, ProtocolUpgrade, EmergencyAction, FundAllocation }
|
||||
|
||||
pub struct AccGovernanceClient { rpc: NRPCClient }
|
||||
/// AccGovernance 协议客户端
|
||||
pub struct AccGovernanceClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccGovernanceClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn create_proposal(
|
||||
&self, proposer: Address, proposal_type: ProposalType,
|
||||
description: &str, voting_duration_secs: u64, constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_governance.create_proposal", &(proposer, proposal_type, description, voting_duration_secs, constitutional_receipt)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn cast_vote(&self, proposal_id: Hash, voter: Address, choice: VoteChoice) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_governance.cast_vote", &(proposal_id, voter, choice)).await
|
||||
/// 创建治理提案
|
||||
pub async fn create_proposal(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_governance.create_proposal", p).await
|
||||
}
|
||||
|
||||
pub async fn finalize_proposal(&self, proposal_id: Hash, constitutional_receipt: Hash) -> Result<bool, NRPCError> {
|
||||
self.rpc.call("acc_governance.finalize_proposal", &(proposal_id, constitutional_receipt)).await
|
||||
/// 投票
|
||||
pub async fn vote(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_governance.vote", p).await
|
||||
}
|
||||
|
||||
/// 执行提案
|
||||
pub async fn execute_proposal(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_governance.execute_proposal", p).await
|
||||
}
|
||||
|
||||
/// 查询提案详情
|
||||
pub async fn get_proposal(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_governance.get_proposal", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,48 @@
|
|||
//! ACC-Insurance 资产保险协议客户端接口
|
||||
//! AccInsurance 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InsuranceType { AssetLoss, PriceVolatility, CustodyRisk, LegalRisk, NaturalDisaster }
|
||||
|
||||
pub struct AccInsuranceClient { rpc: NRPCClient }
|
||||
/// AccInsurance 协议客户端
|
||||
pub struct AccInsuranceClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccInsuranceClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn issue_policy(
|
||||
&self, asset_id: Hash, insured: Address, insurer: Address,
|
||||
insurance_type: InsuranceType, coverage_amount: u128,
|
||||
premium_rate_bps: u16, duration_secs: u64, constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_insurance.issue_policy", &(
|
||||
asset_id, insured, insurer, insurance_type,
|
||||
coverage_amount, premium_rate_bps, duration_secs, constitutional_receipt
|
||||
)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn submit_claim(
|
||||
&self, policy_id: Hash, claimant: Address, claim_amount: u128,
|
||||
reason: &str, evidence_hash: Hash, constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_insurance.submit_claim", &(policy_id, claimant, claim_amount, reason, evidence_hash, constitutional_receipt)).await
|
||||
/// 创建保险策略
|
||||
pub async fn create_policy(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_insurance.create_policy", p).await
|
||||
}
|
||||
|
||||
pub async fn pay_claim(&self, claim_id: Hash, constitutional_receipt: Hash) -> Result<u128, NRPCError> {
|
||||
self.rpc.call("acc_insurance.pay_claim", &(claim_id, constitutional_receipt)).await
|
||||
/// 查询保险策略
|
||||
pub async fn get_policy(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_insurance.get_policy", p).await
|
||||
}
|
||||
|
||||
/// 提交理赔申请
|
||||
pub async fn file_claim(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_insurance.file_claim", p).await
|
||||
}
|
||||
|
||||
/// 处理理赔
|
||||
pub async fn process_claim(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_insurance.process_claim", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,48 @@
|
|||
//! ACC-Redemption 赎回协议客户端接口
|
||||
//! AccRedemption 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub struct AccRedemptionClient { rpc: NRPCClient }
|
||||
/// AccRedemption 协议客户端
|
||||
pub struct AccRedemptionClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccRedemptionClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn fund_pool(&self, asset_id: Hash, amount_xtzh: u128, constitutional_receipt: Hash) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_redemption.fund_redemption_pool", &(asset_id, amount_xtzh, constitutional_receipt)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn request_redemption(
|
||||
&self, asset_id: Hash, redeemer: Address, amount: u128,
|
||||
price_xtzh: u128, constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_redemption.request_redemption", &(asset_id, redeemer, amount, price_xtzh, constitutional_receipt)).await
|
||||
/// 申请赎回
|
||||
pub async fn request_redemption(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_redemption.request_redemption", p).await
|
||||
}
|
||||
|
||||
pub async fn complete_redemption(&self, redemption_id: Hash, constitutional_receipt: Hash) -> Result<u128, NRPCError> {
|
||||
self.rpc.call("acc_redemption.complete_redemption", &(redemption_id, constitutional_receipt)).await
|
||||
/// 批准赎回
|
||||
pub async fn approve_redemption(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_redemption.approve_redemption", p).await
|
||||
}
|
||||
|
||||
/// 查询赎回详情
|
||||
pub async fn get_redemption(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_redemption.get_redemption", p).await
|
||||
}
|
||||
|
||||
/// 取消赎回
|
||||
pub async fn cancel_redemption(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_redemption.cancel_redemption", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,48 @@
|
|||
//! ACC-Reserve 多资产储备协议客户端接口
|
||||
//! AccReserve 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ReserveEntry {
|
||||
pub asset_symbol: String,
|
||||
pub amount: u128,
|
||||
pub custodian: Address,
|
||||
pub last_audit_hash: Option<Hash>,
|
||||
/// AccReserve 协议客户端
|
||||
pub struct AccReserveClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
pub struct AccReserveClient { rpc: NRPCClient }
|
||||
|
||||
impl AccReserveClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn deposit(
|
||||
&self, asset_symbol: &str, amount: u128, custodian: Address,
|
||||
constitutional_receipt: Hash,
|
||||
) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_reserve.deposit", &(asset_symbol, amount, custodian, constitutional_receipt)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn withdraw(
|
||||
&self, asset_symbol: &str, amount: u128, recipient: Address,
|
||||
constitutional_receipt: Hash,
|
||||
) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_reserve.withdraw", &(asset_symbol, amount, recipient, constitutional_receipt)).await
|
||||
/// 查询储备信息
|
||||
pub async fn get_reserve_info(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_reserve.get_reserve_info", p).await
|
||||
}
|
||||
|
||||
pub async fn audit(&self, asset_symbol: &str, audit_hash: Hash) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_reserve.audit", &(asset_symbol, audit_hash)).await
|
||||
/// 增加储备
|
||||
pub async fn add_reserve(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_reserve.add_reserve", p).await
|
||||
}
|
||||
|
||||
pub async fn get_reserve(&self, asset_symbol: &str) -> Result<Option<ReserveEntry>, NRPCError> {
|
||||
self.rpc.call("acc_reserve.get_reserve", &asset_symbol).await
|
||||
/// 提取储备
|
||||
pub async fn withdraw_reserve(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_reserve.withdraw_reserve", p).await
|
||||
}
|
||||
|
||||
/// 查询储备构成
|
||||
pub async fn get_reserve_composition(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_reserve.get_reserve_composition", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +1,58 @@
|
|||
//! ACC-RWA 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
/// RWA 资产类型
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RWAAssetType {
|
||||
RealEstate, Infrastructure, CommodityFund, PrivateEquity,
|
||||
CarbonCredit, IntellectualProperty, ArtAndCollectibles, Other(String),
|
||||
}
|
||||
|
||||
/// RWA 资产记录
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RWAAssetRecord {
|
||||
pub asset_id: Hash,
|
||||
pub gnacs_code: String,
|
||||
pub asset_type: RWAAssetType,
|
||||
pub owner: Address,
|
||||
pub total_supply: u128,
|
||||
pub valuation_xtzh: u128,
|
||||
pub jurisdiction: String,
|
||||
pub is_frozen: bool,
|
||||
}
|
||||
|
||||
/// ACC-RWA 协议客户端
|
||||
/// ACC-RWA 真实世界资产协议客户端
|
||||
pub struct AccRwaClient {
|
||||
rpc: NRPCClient,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccRwaClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 注册 RWA 资产
|
||||
pub async fn register_asset(
|
||||
&self, gnacs_code: &str, asset_type: RWAAssetType, owner: Address,
|
||||
total_supply: u128, initial_valuation_xtzh: u128, jurisdiction: &str,
|
||||
legal_document_hash: Hash, ai_compliance_score: u8,
|
||||
constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_rwa.register_asset", &(
|
||||
gnacs_code, asset_type, owner, total_supply, initial_valuation_xtzh,
|
||||
jurisdiction, legal_document_hash, ai_compliance_score, constitutional_receipt
|
||||
)).await
|
||||
pub async fn register_asset(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_rwa.register_asset", p).await
|
||||
}
|
||||
|
||||
/// 转移 RWA 资产
|
||||
pub async fn transfer_asset(
|
||||
&self, asset_id: Hash, from: Address, to: Address, amount: u128,
|
||||
) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_rwa.transfer_asset", &(asset_id, from, to, amount)).await
|
||||
pub async fn transfer_asset(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_rwa.transfer_asset", p).await
|
||||
}
|
||||
|
||||
/// 冻结资产
|
||||
pub async fn freeze_asset(
|
||||
&self, asset_id: Hash, reason: &str, constitutional_receipt: Hash,
|
||||
) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_rwa.freeze_asset", &(asset_id, reason, constitutional_receipt)).await
|
||||
/// 冻结 RWA 资产
|
||||
pub async fn freeze_asset(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_rwa.freeze_asset", p).await
|
||||
}
|
||||
|
||||
/// 查询资产持仓
|
||||
pub async fn balance_of(&self, asset_id: Hash, holder: Address) -> Result<u128, NRPCError> {
|
||||
self.rpc.call("acc_rwa.balance_of", &(asset_id, holder)).await
|
||||
/// 查询 RWA 资产详情
|
||||
pub async fn get_asset(&self, asset_id: &Hash) -> Result<Value> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"asset_id": asset_id.to_hex(),
|
||||
});
|
||||
self.client.call("acc_rwa.get_asset", params).await
|
||||
}
|
||||
|
||||
/// 查询资产详情
|
||||
pub async fn get_asset(&self, asset_id: Hash) -> Result<Option<RWAAssetRecord>, NRPCError> {
|
||||
self.rpc.call("acc_rwa.get_asset", &asset_id).await
|
||||
/// 查询地址持有的 RWA 资产列表
|
||||
pub async fn get_holdings(&self, owner: &Address) -> Result<Value> {
|
||||
let params = json!({
|
||||
"contract": self.contract_address.to_hex(),
|
||||
"owner": owner.to_hex(),
|
||||
});
|
||||
self.client.call("acc_rwa.get_holdings", params).await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,48 @@
|
|||
//! ACC-Valuation AI 驱动资产估值协议客户端接口
|
||||
//! AccValuation 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
/// 估值结果
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ValuationResult {
|
||||
pub asset_id: Hash,
|
||||
pub value_xtzh: u128,
|
||||
pub ai_confidence: u8,
|
||||
pub timestamp: u64,
|
||||
pub method: String,
|
||||
}
|
||||
|
||||
/// ACC-Valuation 协议客户端
|
||||
/// AccValuation 协议客户端
|
||||
pub struct AccValuationClient {
|
||||
rpc: NRPCClient,
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccValuationClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
/// 提交估值请求
|
||||
pub async fn request_valuation(
|
||||
&self, asset_id: Hash, gnacs_code: &str, asset_data: Vec<u8>,
|
||||
constitutional_receipt: Hash,
|
||||
) -> Result<Hash, NRPCError> {
|
||||
self.rpc.call("acc_valuation.request_valuation", &(asset_id, gnacs_code, asset_data, constitutional_receipt)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
/// 获取最新估值
|
||||
pub async fn get_valuation(&self, asset_id: Hash) -> Result<Option<ValuationResult>, NRPCError> {
|
||||
self.rpc.call("acc_valuation.get_valuation", &asset_id).await
|
||||
/// 查询资产估值
|
||||
pub async fn get_valuation(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_valuation.get_valuation", p).await
|
||||
}
|
||||
|
||||
/// 获取估值历史
|
||||
pub async fn get_history(&self, asset_id: Hash) -> Result<Vec<ValuationResult>, NRPCError> {
|
||||
self.rpc.call("acc_valuation.get_valuation_history", &asset_id).await
|
||||
/// 更新资产估值
|
||||
pub async fn update_valuation(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_valuation.update_valuation", p).await
|
||||
}
|
||||
|
||||
/// 查询估值历史
|
||||
pub async fn get_history(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_valuation.get_history", p).await
|
||||
}
|
||||
|
||||
/// 请求 AI 估值
|
||||
pub async fn request_ai_valuation(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_valuation.request_ai_valuation", p).await
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,48 @@
|
|||
//! ACC-XTZH 稳定币协议客户端接口(SDR锚定+黄金储备)
|
||||
//! AccXtzh 协议客户端接口
|
||||
//! NAC 原生 SDK - 通过 NRPC4.0 与链交互
|
||||
|
||||
use crate::types::{Address, Hash, NRPCClient, NRPCError};
|
||||
use crate::error::{NACError, Result};
|
||||
use crate::adapters::NacLensClient;
|
||||
use nac_udm::primitives::{Address, Hash};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub struct AccXtzhClient { rpc: NRPCClient }
|
||||
/// AccXtzh 协议客户端
|
||||
pub struct AccXtzhClient {
|
||||
pub client: NacLensClient,
|
||||
pub contract_address: Address,
|
||||
}
|
||||
|
||||
impl AccXtzhClient {
|
||||
pub fn new(rpc: NRPCClient) -> Self { Self { rpc } }
|
||||
|
||||
pub async fn mint(&self, recipient: Address, amount: u128, constitutional_receipt: Hash) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_xtzh.mint", &(recipient, amount, constitutional_receipt)).await
|
||||
pub fn new(client: NacLensClient, contract_address: Address) -> Self {
|
||||
Self { client, contract_address }
|
||||
}
|
||||
|
||||
pub async fn burn(&self, holder: Address, amount: u128, constitutional_receipt: Hash) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_xtzh.burn", &(holder, amount, constitutional_receipt)).await
|
||||
/// 查询 XTZH 汇率
|
||||
pub async fn get_rate(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_xtzh.get_rate", p).await
|
||||
}
|
||||
|
||||
pub async fn transfer(&self, from: Address, to: Address, amount: u128) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_xtzh.transfer", &(from, to, amount)).await
|
||||
/// 铸造 XTZH 稳定币
|
||||
pub async fn mint_xtzh(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_xtzh.mint_xtzh", p).await
|
||||
}
|
||||
|
||||
pub async fn balance_of(&self, address: Address) -> Result<u128, NRPCError> {
|
||||
self.rpc.call("acc_xtzh.balance_of", &address).await
|
||||
/// 赎回 XTZH 稳定币
|
||||
pub async fn redeem_xtzh(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_xtzh.redeem_xtzh", p).await
|
||||
}
|
||||
|
||||
pub async fn total_supply(&self) -> Result<u128, NRPCError> {
|
||||
self.rpc.call("acc_xtzh.total_supply", &()).await
|
||||
/// 查询储备率
|
||||
pub async fn get_reserve_ratio(&self, params: Value) -> Result<Value> {
|
||||
let mut p = params;
|
||||
p["contract"] = json!(self.contract_address.to_hex());
|
||||
self.client.call("acc_xtzh.get_reserve_ratio", p).await
|
||||
}
|
||||
|
||||
pub async fn update_sdr_rate(&self, new_rate: u128, constitutional_receipt: Hash) -> Result<(), NRPCError> {
|
||||
self.rpc.call("acc_xtzh.update_sdr_rate", &(new_rate, constitutional_receipt)).await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,20 +62,20 @@ mod acc_collateral;
|
|||
mod acc_redemption;
|
||||
mod acc_insurance;
|
||||
mod acc_governance;
|
||||
pub use acc_rwa::{AccRwaClient, RWAAssetType, RWAAssetRecord};
|
||||
pub use acc_compliance::{AccComplianceClient, SevenLayerComplianceResult, ComplianceRecord};
|
||||
pub use acc_valuation::{AccValuationClient, ValuationResult};
|
||||
pub use acc_custody::{AccCustodyClient, CustodyType, CustodyRecord};
|
||||
pub use acc_collateral::{AccCollateralClient, CollateralRecord};
|
||||
pub use acc_rwa::AccRwaClient;
|
||||
pub use acc_compliance::AccComplianceClient;
|
||||
pub use acc_valuation::AccValuationClient;
|
||||
pub use acc_custody::AccCustodyClient;
|
||||
pub use acc_collateral::AccCollateralClient;
|
||||
pub use acc_redemption::AccRedemptionClient;
|
||||
pub use acc_insurance::{AccInsuranceClient, InsuranceType};
|
||||
pub use acc_governance::{AccGovernanceClient, VoteChoice, ProposalType};
|
||||
pub use acc_insurance::AccInsuranceClient;
|
||||
pub use acc_governance::AccGovernanceClient;
|
||||
|
||||
// === 稳定币与储备协议 ===
|
||||
mod acc_xtzh;
|
||||
mod acc_reserve;
|
||||
pub use acc_xtzh::AccXtzhClient;
|
||||
pub use acc_reserve::{AccReserveClient, ReserveEntry};
|
||||
pub use acc_reserve::AccReserveClient;
|
||||
|
||||
// === 证券代币协议族 ===
|
||||
mod acc1410;
|
||||
|
|
@ -86,5 +86,5 @@ mod acc1644;
|
|||
pub use acc1410::{Acc1410Client, PartitionType, ExtendedGNACS};
|
||||
pub use acc1400::Acc1400Client;
|
||||
pub use acc1594::Acc1594Client;
|
||||
pub use acc1643::{Acc1643Client, AssetDocument};
|
||||
pub use acc1643::Acc1643Client;
|
||||
pub use acc1644::Acc1644Client;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ pub struct NacLensResponse {
|
|||
|
||||
/// 错误(失败时)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<NAC Lens3Error>,
|
||||
pub error: Option<NacLensProtocolError>,
|
||||
|
||||
/// 宪法收据(可选,某些操作会返回)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -76,7 +76,7 @@ pub struct NacLensResponse {
|
|||
|
||||
/// NAC Lens错误
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NAC Lens3Error {
|
||||
pub struct NacLensProtocolError {
|
||||
/// 错误代码
|
||||
pub code: i32,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,177 +1,177 @@
|
|||
//! acc_compliance - NAC 原生协议实现
|
||||
//! 从 acc_remaining_protocols.rs 提取
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCComplianceError {
|
||||
EntityNotFound(Address),
|
||||
ComplianceCheckFailed { layer: u8, reason: String },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
BlacklistedEntity(Address),
|
||||
JurisdictionRestricted { entity: Address, jurisdiction: String },
|
||||
}
|
||||
impl std::fmt::Display for ACCComplianceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::EntityNotFound(a) => write!(f, "实体不存在: {}", a.to_hex()),
|
||||
Self::ComplianceCheckFailed { layer, reason } => write!(f, "第{}层合规检查失败: {}", layer, reason),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::BlacklistedEntity(a) => write!(f, "黑名单实体: {}", a.to_hex()),
|
||||
Self::JurisdictionRestricted { entity, jurisdiction } => write!(f, "司法管辖区限制 {} 在 {}", entity.to_hex(), jurisdiction),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCComplianceError {
|
||||
EntityNotFound(Address),
|
||||
ComplianceCheckFailed { layer: u8, reason: String },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
BlacklistedEntity(Address),
|
||||
JurisdictionRestricted { entity: Address, jurisdiction: String },
|
||||
}
|
||||
impl std::fmt::Display for ACCComplianceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::EntityNotFound(a) => write!(f, "实体不存在: {}", a.to_hex()),
|
||||
Self::ComplianceCheckFailed { layer, reason } => write!(f, "第{}层合规检查失败: {}", layer, reason),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::BlacklistedEntity(a) => write!(f, "黑名单实体: {}", a.to_hex()),
|
||||
Self::JurisdictionRestricted { entity, jurisdiction } => write!(f, "司法管辖区限制 {} 在 {}", entity.to_hex(), jurisdiction),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 七层合规验证结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SevenLayerComplianceResult {
|
||||
pub entity: Address,
|
||||
/// L1: 身份验证
|
||||
pub l1_identity: bool,
|
||||
/// L2: KYC/AML
|
||||
pub l2_kyc_aml: bool,
|
||||
/// L3: 司法管辖区合规
|
||||
pub l3_jurisdiction: bool,
|
||||
/// L4: 资产合规
|
||||
pub l4_asset: bool,
|
||||
/// L5: 交易合规
|
||||
pub l5_transaction: bool,
|
||||
/// L6: AI 合规评分
|
||||
pub l6_ai_score: u8,
|
||||
/// L7: 宪法合规(CBPP)
|
||||
pub l7_constitutional: bool,
|
||||
pub overall_pass: bool,
|
||||
pub checked_at: Timestamp,
|
||||
pub constitutional_receipt: Hash,
|
||||
}
|
||||
impl SevenLayerComplianceResult {
|
||||
pub fn is_fully_compliant(&self) -> bool {
|
||||
self.l1_identity && self.l2_kyc_aml && self.l3_jurisdiction
|
||||
&& self.l4_asset && self.l5_transaction
|
||||
&& self.l6_ai_score >= 70 && self.l7_constitutional
|
||||
}
|
||||
/// 七层合规验证结果
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SevenLayerComplianceResult {
|
||||
pub entity: Address,
|
||||
/// L1: 身份验证
|
||||
pub l1_identity: bool,
|
||||
/// L2: KYC/AML
|
||||
pub l2_kyc_aml: bool,
|
||||
/// L3: 司法管辖区合规
|
||||
pub l3_jurisdiction: bool,
|
||||
/// L4: 资产合规
|
||||
pub l4_asset: bool,
|
||||
/// L5: 交易合规
|
||||
pub l5_transaction: bool,
|
||||
/// L6: AI 合规评分
|
||||
pub l6_ai_score: u8,
|
||||
/// L7: 宪法合规(CBPP)
|
||||
pub l7_constitutional: bool,
|
||||
pub overall_pass: bool,
|
||||
pub checked_at: Timestamp,
|
||||
pub constitutional_receipt: Hash,
|
||||
}
|
||||
impl SevenLayerComplianceResult {
|
||||
pub fn is_fully_compliant(&self) -> bool {
|
||||
self.l1_identity && self.l2_kyc_aml && self.l3_jurisdiction
|
||||
&& self.l4_asset && self.l5_transaction
|
||||
&& self.l6_ai_score >= 70 && self.l7_constitutional
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ComplianceRecord {
|
||||
pub entity: Address,
|
||||
pub kyc_verified: bool,
|
||||
pub aml_cleared: bool,
|
||||
pub allowed_jurisdictions: Vec<String>,
|
||||
pub blacklisted: bool,
|
||||
pub ai_risk_score: u8,
|
||||
pub last_checked: Timestamp,
|
||||
pub compliance_hash: Hash,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ComplianceRecord {
|
||||
pub entity: Address,
|
||||
pub kyc_verified: bool,
|
||||
pub aml_cleared: bool,
|
||||
pub allowed_jurisdictions: Vec<String>,
|
||||
pub blacklisted: bool,
|
||||
pub ai_risk_score: u8,
|
||||
pub last_checked: Timestamp,
|
||||
pub compliance_hash: Hash,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ComplianceProtocolEvent {
|
||||
EntityRegistered { entity: Address, timestamp: Timestamp },
|
||||
ComplianceChecked { entity: Address, result: bool, timestamp: Timestamp },
|
||||
EntityBlacklisted { entity: Address, reason: String, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
EntityWhitelisted { entity: Address, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ComplianceProtocolEvent {
|
||||
EntityRegistered { entity: Address, timestamp: Timestamp },
|
||||
ComplianceChecked { entity: Address, result: bool, timestamp: Timestamp },
|
||||
EntityBlacklisted { entity: Address, reason: String, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
EntityWhitelisted { entity: Address, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
}
|
||||
|
||||
/// ACC-Compliance 七层合规验证协议
|
||||
/// UID: nac.acc.ACCComplianceProtocol.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCComplianceProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub compliance_records: HashMap<Address, ComplianceRecord>,
|
||||
pub blacklist: HashMap<Address, String>,
|
||||
pub compliance_history: HashMap<Address, Vec<SevenLayerComplianceResult>>,
|
||||
pub pending_events: Vec<ComplianceProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
/// ACC-Compliance 七层合规验证协议
|
||||
/// UID: nac.acc.ACCComplianceProtocol.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCComplianceProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub compliance_records: HashMap<Address, ComplianceRecord>,
|
||||
pub blacklist: HashMap<Address, String>,
|
||||
pub compliance_history: HashMap<Address, Vec<SevenLayerComplianceResult>>,
|
||||
pub pending_events: Vec<ComplianceProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCComplianceProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCComplianceProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Compliance".to_string(),
|
||||
compliance_records: HashMap::new(),
|
||||
blacklist: HashMap::new(),
|
||||
compliance_history: HashMap::new(),
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
impl ACCComplianceProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCComplianceProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Compliance".to_string(),
|
||||
compliance_records: HashMap::new(),
|
||||
blacklist: HashMap::new(),
|
||||
compliance_history: HashMap::new(),
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
pub fn register_entity(
|
||||
&mut self, entity: Address, kyc_verified: bool, aml_cleared: bool,
|
||||
allowed_jurisdictions: Vec<String>, ai_risk_score: u8,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCComplianceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCComplianceError::InvalidConstitutionalReceipt); }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(entity.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let compliance_hash = Hash::sha3_384(&data);
|
||||
let record = ComplianceRecord {
|
||||
entity: entity.clone(), kyc_verified, aml_cleared,
|
||||
allowed_jurisdictions, blacklisted: false, ai_risk_score,
|
||||
last_checked: timestamp.clone(), compliance_hash,
|
||||
};
|
||||
self.compliance_records.insert(entity.clone(), record);
|
||||
self.pending_events.push(ComplianceProtocolEvent::EntityRegistered { entity, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn run_seven_layer_check(
|
||||
&mut self, entity: Address, jurisdiction: &str,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<SevenLayerComplianceResult, ACCComplianceError> {
|
||||
if self.blacklist.contains_key(&entity) {
|
||||
return Err(ACCComplianceError::BlacklistedEntity(entity));
|
||||
}
|
||||
let record = self.compliance_records.get(&entity)
|
||||
.ok_or(ACCComplianceError::EntityNotFound(entity.clone()))?;
|
||||
let l1 = true; // 地址存在即通过身份验证
|
||||
let l2 = record.kyc_verified && record.aml_cleared;
|
||||
let l3 = record.allowed_jurisdictions.is_empty()
|
||||
|| record.allowed_jurisdictions.iter().any(|j| j == jurisdiction);
|
||||
let l4 = !record.blacklisted;
|
||||
let l5 = record.ai_risk_score < 80; // 风险评分低于80才允许
|
||||
let l6 = 100u8.saturating_sub(record.ai_risk_score);
|
||||
let l7 = !constitutional_receipt.is_zero();
|
||||
let overall = l1 && l2 && l3 && l4 && l5 && l6 >= 70 && l7;
|
||||
let result = SevenLayerComplianceResult {
|
||||
entity: entity.clone(), l1_identity: l1, l2_kyc_aml: l2,
|
||||
l3_jurisdiction: l3, l4_asset: l4, l5_transaction: l5,
|
||||
l6_ai_score: l6, l7_constitutional: l7, overall_pass: overall,
|
||||
checked_at: timestamp.clone(), constitutional_receipt,
|
||||
};
|
||||
self.compliance_history.entry(entity.clone()).or_insert_with(Vec::new).push(result.clone());
|
||||
self.pending_events.push(ComplianceProtocolEvent::ComplianceChecked {
|
||||
entity, result: overall, timestamp,
|
||||
});
|
||||
Ok(result)
|
||||
}
|
||||
pub fn blacklist_entity(
|
||||
&mut self, entity: Address, reason: String,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCComplianceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCComplianceError::InvalidConstitutionalReceipt); }
|
||||
self.blacklist.insert(entity.clone(), reason.clone());
|
||||
if let Some(record) = self.compliance_records.get_mut(&entity) {
|
||||
record.blacklisted = true;
|
||||
}
|
||||
self.pending_events.push(ComplianceProtocolEvent::EntityBlacklisted {
|
||||
entity, reason, timestamp, constitutional_receipt,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
pub fn is_compliant(&self, entity: &Address) -> bool {
|
||||
if self.blacklist.contains_key(entity) { return false; }
|
||||
self.compliance_records.get(entity)
|
||||
.map(|r| r.kyc_verified && r.aml_cleared && !r.blacklisted)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
pub fn get_record(&self, entity: &Address) -> Option<&ComplianceRecord> { self.compliance_records.get(entity) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<ComplianceProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
pub fn register_entity(
|
||||
&mut self, entity: Address, kyc_verified: bool, aml_cleared: bool,
|
||||
allowed_jurisdictions: Vec<String>, ai_risk_score: u8,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCComplianceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCComplianceError::InvalidConstitutionalReceipt); }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(entity.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let compliance_hash = Hash::sha3_384(&data);
|
||||
let record = ComplianceRecord {
|
||||
entity: entity.clone(), kyc_verified, aml_cleared,
|
||||
allowed_jurisdictions, blacklisted: false, ai_risk_score,
|
||||
last_checked: timestamp.clone(), compliance_hash,
|
||||
};
|
||||
self.compliance_records.insert(entity.clone(), record);
|
||||
self.pending_events.push(ComplianceProtocolEvent::EntityRegistered { entity, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn run_seven_layer_check(
|
||||
&mut self, entity: Address, jurisdiction: &str,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<SevenLayerComplianceResult, ACCComplianceError> {
|
||||
if self.blacklist.contains_key(&entity) {
|
||||
return Err(ACCComplianceError::BlacklistedEntity(entity));
|
||||
}
|
||||
let record = self.compliance_records.get(&entity)
|
||||
.ok_or(ACCComplianceError::EntityNotFound(entity.clone()))?;
|
||||
let l1 = true; // 地址存在即通过身份验证
|
||||
let l2 = record.kyc_verified && record.aml_cleared;
|
||||
let l3 = record.allowed_jurisdictions.is_empty()
|
||||
|| record.allowed_jurisdictions.iter().any(|j| j == jurisdiction);
|
||||
let l4 = !record.blacklisted;
|
||||
let l5 = record.ai_risk_score < 80; // 风险评分低于80才允许
|
||||
let l6 = 100u8.saturating_sub(record.ai_risk_score);
|
||||
let l7 = !constitutional_receipt.is_zero();
|
||||
let overall = l1 && l2 && l3 && l4 && l5 && l6 >= 70 && l7;
|
||||
let result = SevenLayerComplianceResult {
|
||||
entity: entity.clone(), l1_identity: l1, l2_kyc_aml: l2,
|
||||
l3_jurisdiction: l3, l4_asset: l4, l5_transaction: l5,
|
||||
l6_ai_score: l6, l7_constitutional: l7, overall_pass: overall,
|
||||
checked_at: timestamp.clone(), constitutional_receipt,
|
||||
};
|
||||
self.compliance_history.entry(entity.clone()).or_insert_with(Vec::new).push(result.clone());
|
||||
self.pending_events.push(ComplianceProtocolEvent::ComplianceChecked {
|
||||
entity, result: overall, timestamp,
|
||||
});
|
||||
Ok(result)
|
||||
}
|
||||
pub fn blacklist_entity(
|
||||
&mut self, entity: Address, reason: String,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCComplianceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCComplianceError::InvalidConstitutionalReceipt); }
|
||||
self.blacklist.insert(entity.clone(), reason.clone());
|
||||
if let Some(record) = self.compliance_records.get_mut(&entity) {
|
||||
record.blacklisted = true;
|
||||
}
|
||||
self.pending_events.push(ComplianceProtocolEvent::EntityBlacklisted {
|
||||
entity, reason, timestamp, constitutional_receipt,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
pub fn is_compliant(&self, entity: &Address) -> bool {
|
||||
if self.blacklist.contains_key(entity) { return false; }
|
||||
self.compliance_records.get(entity)
|
||||
.map(|r| r.kyc_verified && r.aml_cleared && !r.blacklisted)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
pub fn get_record(&self, entity: &Address) -> Option<&ComplianceRecord> { self.compliance_records.get(entity) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<ComplianceProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,192 +1,192 @@
|
|||
//! acc_governance - NAC 原生协议实现
|
||||
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCGovernanceError {
|
||||
ProposalNotFound(Hash),
|
||||
ProposalAlreadyExecuted(Hash),
|
||||
VotingPeriodEnded(Hash),
|
||||
AlreadyVoted(Address),
|
||||
InsufficientVotingPower { required: u128, actual: u128 },
|
||||
QuorumNotReached { required: u128, actual: u128 },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
}
|
||||
impl std::fmt::Display for ACCGovernanceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ProposalNotFound(h) => write!(f, "提案不存在: {}", h.to_hex()),
|
||||
Self::ProposalAlreadyExecuted(h) => write!(f, "提案已执行: {}", h.to_hex()),
|
||||
Self::VotingPeriodEnded(h) => write!(f, "投票期已结束: {}", h.to_hex()),
|
||||
Self::AlreadyVoted(a) => write!(f, "已投票: {}", a.to_hex()),
|
||||
Self::InsufficientVotingPower { required, actual } => write!(f, "投票权不足: 需要 {},实际 {}", required, actual),
|
||||
Self::QuorumNotReached { required, actual } => write!(f, "未达法定人数: 需要 {},实际 {}", required, actual),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCGovernanceError {
|
||||
ProposalNotFound(Hash),
|
||||
ProposalAlreadyExecuted(Hash),
|
||||
VotingPeriodEnded(Hash),
|
||||
AlreadyVoted(Address),
|
||||
InsufficientVotingPower { required: u128, actual: u128 },
|
||||
QuorumNotReached { required: u128, actual: u128 },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
}
|
||||
impl std::fmt::Display for ACCGovernanceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ProposalNotFound(h) => write!(f, "提案不存在: {}", h.to_hex()),
|
||||
Self::ProposalAlreadyExecuted(h) => write!(f, "提案已执行: {}", h.to_hex()),
|
||||
Self::VotingPeriodEnded(h) => write!(f, "投票期已结束: {}", h.to_hex()),
|
||||
Self::AlreadyVoted(a) => write!(f, "已投票: {}", a.to_hex()),
|
||||
Self::InsufficientVotingPower { required, actual } => write!(f, "投票权不足: 需要 {},实际 {}", required, actual),
|
||||
Self::QuorumNotReached { required, actual } => write!(f, "未达法定人数: 需要 {},实际 {}", required, actual),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ProposalType {
|
||||
ParameterChange { parameter: String, new_value: Vec<u8> },
|
||||
ProtocolUpgrade { new_version: String, upgrade_hash: Hash },
|
||||
AssetPolicyChange { asset_id: Hash, policy_hash: Hash },
|
||||
EmergencyPause { reason: String },
|
||||
GovernanceMemberChange { member: Address, action: MemberAction },
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum MemberAction { Add, Remove }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ProposalStatus { Active, Passed, Rejected, Executed, Cancelled, Expired }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum VoteChoice { For, Against, Abstain }
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ProposalType {
|
||||
ParameterChange { parameter: String, new_value: Vec<u8> },
|
||||
ProtocolUpgrade { new_version: String, upgrade_hash: Hash },
|
||||
AssetPolicyChange { asset_id: Hash, policy_hash: Hash },
|
||||
EmergencyPause { reason: String },
|
||||
GovernanceMemberChange { member: Address, action: MemberAction },
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum MemberAction { Add, Remove }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ProposalStatus { Active, Passed, Rejected, Executed, Cancelled, Expired }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum VoteChoice { For, Against, Abstain }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GovernanceProposal {
|
||||
pub proposal_id: Hash,
|
||||
pub proposer: Address,
|
||||
pub proposal_type: ProposalType,
|
||||
pub description: String,
|
||||
pub status: ProposalStatus,
|
||||
pub votes_for: u128,
|
||||
pub votes_against: u128,
|
||||
pub votes_abstain: u128,
|
||||
pub vote_records: HashMap<Address, VoteChoice>,
|
||||
pub voting_start: Timestamp,
|
||||
pub voting_end: Timestamp,
|
||||
pub quorum_bps: u32,
|
||||
pub pass_threshold_bps: u32,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub created_at: Timestamp,
|
||||
pub executed_at: Option<Timestamp>,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GovernanceProposal {
|
||||
pub proposal_id: Hash,
|
||||
pub proposer: Address,
|
||||
pub proposal_type: ProposalType,
|
||||
pub description: String,
|
||||
pub status: ProposalStatus,
|
||||
pub votes_for: u128,
|
||||
pub votes_against: u128,
|
||||
pub votes_abstain: u128,
|
||||
pub vote_records: HashMap<Address, VoteChoice>,
|
||||
pub voting_start: Timestamp,
|
||||
pub voting_end: Timestamp,
|
||||
pub quorum_bps: u32,
|
||||
pub pass_threshold_bps: u32,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub created_at: Timestamp,
|
||||
pub executed_at: Option<Timestamp>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum GovernanceProtocolEvent {
|
||||
ProposalCreated { proposal_id: Hash, proposer: Address, timestamp: Timestamp },
|
||||
VoteCast { proposal_id: Hash, voter: Address, choice: VoteChoice, voting_power: u128, timestamp: Timestamp },
|
||||
ProposalPassed { proposal_id: Hash, votes_for: u128, votes_against: u128, timestamp: Timestamp },
|
||||
ProposalRejected { proposal_id: Hash, reason: String, timestamp: Timestamp },
|
||||
ProposalExecuted { proposal_id: Hash, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum GovernanceProtocolEvent {
|
||||
ProposalCreated { proposal_id: Hash, proposer: Address, timestamp: Timestamp },
|
||||
VoteCast { proposal_id: Hash, voter: Address, choice: VoteChoice, voting_power: u128, timestamp: Timestamp },
|
||||
ProposalPassed { proposal_id: Hash, votes_for: u128, votes_against: u128, timestamp: Timestamp },
|
||||
ProposalRejected { proposal_id: Hash, reason: String, timestamp: Timestamp },
|
||||
ProposalExecuted { proposal_id: Hash, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCGovernanceProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub proposals: HashMap<Hash, GovernanceProposal>,
|
||||
pub voting_power_registry: HashMap<Address, u128>,
|
||||
pub total_voting_power: u128,
|
||||
pub default_quorum_bps: u32,
|
||||
pub default_pass_threshold_bps: u32,
|
||||
pub pending_events: Vec<GovernanceProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCGovernanceProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub proposals: HashMap<Hash, GovernanceProposal>,
|
||||
pub voting_power_registry: HashMap<Address, u128>,
|
||||
pub total_voting_power: u128,
|
||||
pub default_quorum_bps: u32,
|
||||
pub default_pass_threshold_bps: u32,
|
||||
pub pending_events: Vec<GovernanceProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCGovernanceProtocol {
|
||||
pub fn new(default_quorum_bps: u32, default_pass_threshold_bps: u32) -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCGovernanceProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Governance".to_string(),
|
||||
proposals: HashMap::new(),
|
||||
voting_power_registry: HashMap::new(),
|
||||
total_voting_power: 0,
|
||||
default_quorum_bps, default_pass_threshold_bps,
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(), updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
impl ACCGovernanceProtocol {
|
||||
pub fn new(default_quorum_bps: u32, default_pass_threshold_bps: u32) -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCGovernanceProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Governance".to_string(),
|
||||
proposals: HashMap::new(),
|
||||
voting_power_registry: HashMap::new(),
|
||||
total_voting_power: 0,
|
||||
default_quorum_bps, default_pass_threshold_bps,
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(), updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
pub fn register_voting_power(&mut self, address: Address, power: u128) {
|
||||
let old = self.voting_power_registry.insert(address, power).unwrap_or(0);
|
||||
self.total_voting_power = self.total_voting_power.saturating_sub(old).saturating_add(power);
|
||||
}
|
||||
pub fn create_proposal(
|
||||
&mut self, proposer: Address, proposal_type: ProposalType, description: String,
|
||||
voting_duration_secs: u64, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCGovernanceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCGovernanceError::InvalidConstitutionalReceipt); }
|
||||
let proposer_power = self.voting_power_registry.get(&proposer).copied().unwrap_or(0);
|
||||
if proposer_power == 0 {
|
||||
return Err(ACCGovernanceError::InsufficientVotingPower { required: 1, actual: 0 });
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(proposer.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let proposal_id = Hash::sha3_384(&data);
|
||||
let proposal = GovernanceProposal {
|
||||
proposal_id, proposer: proposer.clone(), proposal_type, description,
|
||||
status: ProposalStatus::Active,
|
||||
votes_for: 0, votes_against: 0, votes_abstain: 0,
|
||||
vote_records: HashMap::new(),
|
||||
voting_start: timestamp.clone(),
|
||||
voting_end: timestamp.add_secs(voting_duration_secs),
|
||||
quorum_bps: self.default_quorum_bps,
|
||||
pass_threshold_bps: self.default_pass_threshold_bps,
|
||||
constitutional_receipt, created_at: timestamp.clone(), executed_at: None,
|
||||
};
|
||||
self.proposals.insert(proposal_id, proposal);
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalCreated { proposal_id, proposer, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(proposal_id)
|
||||
}
|
||||
pub fn cast_vote(
|
||||
&mut self, proposal_id: Hash, voter: Address, choice: VoteChoice, timestamp: Timestamp,
|
||||
) -> Result<(), ACCGovernanceError> {
|
||||
let voting_power = self.voting_power_registry.get(&voter).copied().unwrap_or(0);
|
||||
if voting_power == 0 {
|
||||
return Err(ACCGovernanceError::InsufficientVotingPower { required: 1, actual: 0 });
|
||||
}
|
||||
let proposal = self.proposals.get_mut(&proposal_id)
|
||||
.ok_or(ACCGovernanceError::ProposalNotFound(proposal_id))?;
|
||||
if proposal.status != ProposalStatus::Active {
|
||||
return Err(ACCGovernanceError::VotingPeriodEnded(proposal_id));
|
||||
}
|
||||
if proposal.vote_records.contains_key(&voter) {
|
||||
return Err(ACCGovernanceError::AlreadyVoted(voter));
|
||||
}
|
||||
match choice {
|
||||
VoteChoice::For => proposal.votes_for = proposal.votes_for.saturating_add(voting_power),
|
||||
VoteChoice::Against => proposal.votes_against = proposal.votes_against.saturating_add(voting_power),
|
||||
VoteChoice::Abstain => proposal.votes_abstain = proposal.votes_abstain.saturating_add(voting_power),
|
||||
}
|
||||
proposal.vote_records.insert(voter.clone(), choice);
|
||||
self.pending_events.push(GovernanceProtocolEvent::VoteCast { proposal_id, voter, choice, voting_power, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn finalize_proposal(
|
||||
&mut self, proposal_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<bool, ACCGovernanceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCGovernanceError::InvalidConstitutionalReceipt); }
|
||||
let proposal = self.proposals.get_mut(&proposal_id)
|
||||
.ok_or(ACCGovernanceError::ProposalNotFound(proposal_id))?;
|
||||
let total_votes = proposal.votes_for + proposal.votes_against + proposal.votes_abstain;
|
||||
let quorum_required = (self.total_voting_power as u64 * proposal.quorum_bps as u64 / 10000) as u128;
|
||||
if total_votes < quorum_required {
|
||||
proposal.status = ProposalStatus::Rejected;
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalRejected {
|
||||
proposal_id, reason: format!("未达法定人数: {} < {}", total_votes, quorum_required), timestamp,
|
||||
});
|
||||
return Ok(false);
|
||||
}
|
||||
let effective_votes = proposal.votes_for + proposal.votes_against;
|
||||
let pass_required = (effective_votes as u64 * proposal.pass_threshold_bps as u64 / 10000) as u128;
|
||||
let passed = proposal.votes_for >= pass_required;
|
||||
if passed {
|
||||
proposal.status = ProposalStatus::Executed;
|
||||
proposal.executed_at = Some(timestamp.clone());
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalExecuted { proposal_id, timestamp, constitutional_receipt });
|
||||
} else {
|
||||
proposal.status = ProposalStatus::Rejected;
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalRejected {
|
||||
proposal_id, reason: "赞成票未达阈值".to_string(), timestamp,
|
||||
});
|
||||
}
|
||||
Ok(passed)
|
||||
}
|
||||
pub fn get_proposal(&self, id: &Hash) -> Option<&GovernanceProposal> { self.proposals.get(id) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<GovernanceProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
pub fn register_voting_power(&mut self, address: Address, power: u128) {
|
||||
let old = self.voting_power_registry.insert(address, power).unwrap_or(0);
|
||||
self.total_voting_power = self.total_voting_power.saturating_sub(old).saturating_add(power);
|
||||
}
|
||||
pub fn create_proposal(
|
||||
&mut self, proposer: Address, proposal_type: ProposalType, description: String,
|
||||
voting_duration_secs: u64, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCGovernanceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCGovernanceError::InvalidConstitutionalReceipt); }
|
||||
let proposer_power = self.voting_power_registry.get(&proposer).copied().unwrap_or(0);
|
||||
if proposer_power == 0 {
|
||||
return Err(ACCGovernanceError::InsufficientVotingPower { required: 1, actual: 0 });
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(proposer.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let proposal_id = Hash::sha3_384(&data);
|
||||
let proposal = GovernanceProposal {
|
||||
proposal_id, proposer: proposer.clone(), proposal_type, description,
|
||||
status: ProposalStatus::Active,
|
||||
votes_for: 0, votes_against: 0, votes_abstain: 0,
|
||||
vote_records: HashMap::new(),
|
||||
voting_start: timestamp.clone(),
|
||||
voting_end: timestamp.add_secs(voting_duration_secs),
|
||||
quorum_bps: self.default_quorum_bps,
|
||||
pass_threshold_bps: self.default_pass_threshold_bps,
|
||||
constitutional_receipt, created_at: timestamp.clone(), executed_at: None,
|
||||
};
|
||||
self.proposals.insert(proposal_id, proposal);
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalCreated { proposal_id, proposer, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(proposal_id)
|
||||
}
|
||||
pub fn cast_vote(
|
||||
&mut self, proposal_id: Hash, voter: Address, choice: VoteChoice, timestamp: Timestamp,
|
||||
) -> Result<(), ACCGovernanceError> {
|
||||
let voting_power = self.voting_power_registry.get(&voter).copied().unwrap_or(0);
|
||||
if voting_power == 0 {
|
||||
return Err(ACCGovernanceError::InsufficientVotingPower { required: 1, actual: 0 });
|
||||
}
|
||||
let proposal = self.proposals.get_mut(&proposal_id)
|
||||
.ok_or(ACCGovernanceError::ProposalNotFound(proposal_id))?;
|
||||
if proposal.status != ProposalStatus::Active {
|
||||
return Err(ACCGovernanceError::VotingPeriodEnded(proposal_id));
|
||||
}
|
||||
if proposal.vote_records.contains_key(&voter) {
|
||||
return Err(ACCGovernanceError::AlreadyVoted(voter));
|
||||
}
|
||||
match choice {
|
||||
VoteChoice::For => proposal.votes_for = proposal.votes_for.saturating_add(voting_power),
|
||||
VoteChoice::Against => proposal.votes_against = proposal.votes_against.saturating_add(voting_power),
|
||||
VoteChoice::Abstain => proposal.votes_abstain = proposal.votes_abstain.saturating_add(voting_power),
|
||||
}
|
||||
proposal.vote_records.insert(voter.clone(), choice);
|
||||
self.pending_events.push(GovernanceProtocolEvent::VoteCast { proposal_id, voter, choice, voting_power, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn finalize_proposal(
|
||||
&mut self, proposal_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<bool, ACCGovernanceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCGovernanceError::InvalidConstitutionalReceipt); }
|
||||
let proposal = self.proposals.get_mut(&proposal_id)
|
||||
.ok_or(ACCGovernanceError::ProposalNotFound(proposal_id))?;
|
||||
let total_votes = proposal.votes_for + proposal.votes_against + proposal.votes_abstain;
|
||||
let quorum_required = (self.total_voting_power as u64 * proposal.quorum_bps as u64 / 10000) as u128;
|
||||
if total_votes < quorum_required {
|
||||
proposal.status = ProposalStatus::Rejected;
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalRejected {
|
||||
proposal_id, reason: format!("未达法定人数: {} < {}", total_votes, quorum_required), timestamp,
|
||||
});
|
||||
return Ok(false);
|
||||
}
|
||||
let effective_votes = proposal.votes_for + proposal.votes_against;
|
||||
let pass_required = (effective_votes as u64 * proposal.pass_threshold_bps as u64 / 10000) as u128;
|
||||
let passed = proposal.votes_for >= pass_required;
|
||||
if passed {
|
||||
proposal.status = ProposalStatus::Executed;
|
||||
proposal.executed_at = Some(timestamp.clone());
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalExecuted { proposal_id, timestamp, constitutional_receipt });
|
||||
} else {
|
||||
proposal.status = ProposalStatus::Rejected;
|
||||
self.pending_events.push(GovernanceProtocolEvent::ProposalRejected {
|
||||
proposal_id, reason: "赞成票未达阈值".to_string(), timestamp,
|
||||
});
|
||||
}
|
||||
Ok(passed)
|
||||
}
|
||||
pub fn get_proposal(&self, id: &Hash) -> Option<&GovernanceProposal> { self.proposals.get(id) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<GovernanceProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,168 +1,168 @@
|
|||
//! acc_insurance - NAC 原生协议实现
|
||||
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCInsuranceError {
|
||||
PolicyNotFound(Hash),
|
||||
PolicyExpired(Hash),
|
||||
ClaimAlreadyProcessed(Hash),
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
ClaimExceedsCoverage { coverage: u128, claim: u128 },
|
||||
}
|
||||
impl std::fmt::Display for ACCInsuranceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::PolicyNotFound(h) => write!(f, "保险单不存在: {}", h.to_hex()),
|
||||
Self::PolicyExpired(h) => write!(f, "保险单已过期: {}", h.to_hex()),
|
||||
Self::ClaimAlreadyProcessed(h) => write!(f, "理赔已处理: {}", h.to_hex()),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::ClaimExceedsCoverage { coverage, claim } => write!(f, "理赔超额: 保额 {},理赔 {}", coverage, claim),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCInsuranceError {
|
||||
PolicyNotFound(Hash),
|
||||
PolicyExpired(Hash),
|
||||
ClaimAlreadyProcessed(Hash),
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
ClaimExceedsCoverage { coverage: u128, claim: u128 },
|
||||
}
|
||||
impl std::fmt::Display for ACCInsuranceError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::PolicyNotFound(h) => write!(f, "保险单不存在: {}", h.to_hex()),
|
||||
Self::PolicyExpired(h) => write!(f, "保险单已过期: {}", h.to_hex()),
|
||||
Self::ClaimAlreadyProcessed(h) => write!(f, "理赔已处理: {}", h.to_hex()),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::ClaimExceedsCoverage { coverage, claim } => write!(f, "理赔超额: 保额 {},理赔 {}", coverage, claim),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum InsuranceType { AssetLoss, CustodyRisk, ComplianceRisk, MarketPrice, Comprehensive }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum InsuranceType { AssetLoss, CustodyRisk, ComplianceRisk, MarketPrice, Comprehensive }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InsurancePolicy {
|
||||
pub policy_id: Hash,
|
||||
pub asset_id: Hash,
|
||||
pub insured: Address,
|
||||
pub insurer: Address,
|
||||
pub insurance_type: InsuranceType,
|
||||
pub coverage_amount: u128,
|
||||
pub claimed_amount: u128,
|
||||
pub premium_rate_bps: u16,
|
||||
pub start_time: Timestamp,
|
||||
pub end_time: Timestamp,
|
||||
pub is_active: bool,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub created_at: Timestamp,
|
||||
}
|
||||
impl InsurancePolicy {
|
||||
pub fn is_expired(&self) -> bool { self.end_time.is_expired(0) }
|
||||
pub fn remaining_coverage(&self) -> u128 { self.coverage_amount.saturating_sub(self.claimed_amount) }
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InsurancePolicy {
|
||||
pub policy_id: Hash,
|
||||
pub asset_id: Hash,
|
||||
pub insured: Address,
|
||||
pub insurer: Address,
|
||||
pub insurance_type: InsuranceType,
|
||||
pub coverage_amount: u128,
|
||||
pub claimed_amount: u128,
|
||||
pub premium_rate_bps: u16,
|
||||
pub start_time: Timestamp,
|
||||
pub end_time: Timestamp,
|
||||
pub is_active: bool,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub created_at: Timestamp,
|
||||
}
|
||||
impl InsurancePolicy {
|
||||
pub fn is_expired(&self) -> bool { self.end_time.is_expired(0) }
|
||||
pub fn remaining_coverage(&self) -> u128 { self.coverage_amount.saturating_sub(self.claimed_amount) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ClaimStatus { Pending, UnderReview, Approved, Rejected, Paid }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ClaimStatus { Pending, UnderReview, Approved, Rejected, Paid }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InsuranceClaim {
|
||||
pub claim_id: Hash,
|
||||
pub policy_id: Hash,
|
||||
pub claimant: Address,
|
||||
pub claim_amount: u128,
|
||||
pub claim_reason: String,
|
||||
pub evidence_hash: Hash,
|
||||
pub status: ClaimStatus,
|
||||
pub submitted_at: Timestamp,
|
||||
pub processed_at: Option<Timestamp>,
|
||||
pub constitutional_receipt: Hash,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InsuranceClaim {
|
||||
pub claim_id: Hash,
|
||||
pub policy_id: Hash,
|
||||
pub claimant: Address,
|
||||
pub claim_amount: u128,
|
||||
pub claim_reason: String,
|
||||
pub evidence_hash: Hash,
|
||||
pub status: ClaimStatus,
|
||||
pub submitted_at: Timestamp,
|
||||
pub processed_at: Option<Timestamp>,
|
||||
pub constitutional_receipt: Hash,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InsuranceProtocolEvent {
|
||||
PolicyIssued { policy_id: Hash, asset_id: Hash, insured: Address, coverage: u128, timestamp: Timestamp },
|
||||
ClaimSubmitted { claim_id: Hash, policy_id: Hash, amount: u128, timestamp: Timestamp },
|
||||
ClaimPaid { claim_id: Hash, amount: u128, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InsuranceProtocolEvent {
|
||||
PolicyIssued { policy_id: Hash, asset_id: Hash, insured: Address, coverage: u128, timestamp: Timestamp },
|
||||
ClaimSubmitted { claim_id: Hash, policy_id: Hash, amount: u128, timestamp: Timestamp },
|
||||
ClaimPaid { claim_id: Hash, amount: u128, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCInsuranceProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub policies: HashMap<Hash, InsurancePolicy>,
|
||||
pub claims: HashMap<Hash, InsuranceClaim>,
|
||||
pub insurance_pool: u128,
|
||||
pub pending_events: Vec<InsuranceProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCInsuranceProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCInsuranceProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Insurance".to_string(),
|
||||
policies: HashMap::new(), claims: HashMap::new(),
|
||||
insurance_pool: 0, pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(), updated_at: Timestamp::now(),
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCInsuranceProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub policies: HashMap<Hash, InsurancePolicy>,
|
||||
pub claims: HashMap<Hash, InsuranceClaim>,
|
||||
pub insurance_pool: u128,
|
||||
pub pending_events: Vec<InsuranceProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCInsuranceProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCInsuranceProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Insurance".to_string(),
|
||||
policies: HashMap::new(), claims: HashMap::new(),
|
||||
insurance_pool: 0, pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(), updated_at: Timestamp::now(),
|
||||
}
|
||||
pub fn fund_pool(&mut self, amount: u128) { self.insurance_pool = self.insurance_pool.saturating_add(amount); }
|
||||
pub fn issue_policy(
|
||||
&mut self, asset_id: Hash, insured: Address, insurer: Address,
|
||||
insurance_type: InsuranceType, coverage_amount: u128, premium_rate_bps: u16,
|
||||
duration_secs: u64, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCInsuranceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCInsuranceError::InvalidConstitutionalReceipt); }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(asset_id.as_bytes());
|
||||
data.extend_from_slice(insured.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let policy_id = Hash::sha3_384(&data);
|
||||
let policy = InsurancePolicy {
|
||||
policy_id, asset_id, insured: insured.clone(), insurer, insurance_type,
|
||||
coverage_amount, claimed_amount: 0, premium_rate_bps,
|
||||
start_time: timestamp.clone(),
|
||||
end_time: timestamp.add_secs(duration_secs),
|
||||
is_active: true, constitutional_receipt, created_at: timestamp.clone(),
|
||||
};
|
||||
self.policies.insert(policy_id, policy);
|
||||
self.pending_events.push(InsuranceProtocolEvent::PolicyIssued {
|
||||
policy_id, asset_id, insured, coverage: coverage_amount, timestamp,
|
||||
});
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(policy_id)
|
||||
}
|
||||
pub fn submit_claim(
|
||||
&mut self, policy_id: Hash, claimant: Address, claim_amount: u128,
|
||||
claim_reason: String, evidence_hash: Hash, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCInsuranceError> {
|
||||
let policy = self.policies.get(&policy_id).ok_or(ACCInsuranceError::PolicyNotFound(policy_id))?;
|
||||
if policy.is_expired() { return Err(ACCInsuranceError::PolicyExpired(policy_id)); }
|
||||
if claim_amount > policy.remaining_coverage() {
|
||||
return Err(ACCInsuranceError::ClaimExceedsCoverage { coverage: policy.remaining_coverage(), claim: claim_amount });
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(policy_id.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let claim_id = Hash::sha3_384(&data);
|
||||
let claim = InsuranceClaim {
|
||||
claim_id, policy_id, claimant, claim_amount, claim_reason,
|
||||
evidence_hash, status: ClaimStatus::Pending,
|
||||
submitted_at: timestamp.clone(), processed_at: None, constitutional_receipt,
|
||||
};
|
||||
self.claims.insert(claim_id, claim);
|
||||
self.pending_events.push(InsuranceProtocolEvent::ClaimSubmitted { claim_id, policy_id, amount: claim_amount, timestamp });
|
||||
Ok(claim_id)
|
||||
}
|
||||
pub fn pay_claim(
|
||||
&mut self, claim_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<u128, ACCInsuranceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCInsuranceError::InvalidConstitutionalReceipt); }
|
||||
let claim = self.claims.get_mut(&claim_id).ok_or(ACCInsuranceError::PolicyNotFound(claim_id))?;
|
||||
if claim.status != ClaimStatus::Pending && claim.status != ClaimStatus::UnderReview {
|
||||
return Err(ACCInsuranceError::ClaimAlreadyProcessed(claim_id));
|
||||
}
|
||||
let amount = claim.claim_amount;
|
||||
let policy_id = claim.policy_id;
|
||||
claim.status = ClaimStatus::Paid;
|
||||
claim.processed_at = Some(timestamp.clone());
|
||||
if let Some(policy) = self.policies.get_mut(&policy_id) {
|
||||
policy.claimed_amount = policy.claimed_amount.saturating_add(amount);
|
||||
}
|
||||
self.insurance_pool = self.insurance_pool.saturating_sub(amount);
|
||||
self.pending_events.push(InsuranceProtocolEvent::ClaimPaid { claim_id, amount, timestamp, constitutional_receipt });
|
||||
Ok(amount)
|
||||
}
|
||||
pub fn get_policy(&self, id: &Hash) -> Option<&InsurancePolicy> { self.policies.get(id) }
|
||||
pub fn get_claim(&self, id: &Hash) -> Option<&InsuranceClaim> { self.claims.get(id) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<InsuranceProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
pub fn fund_pool(&mut self, amount: u128) { self.insurance_pool = self.insurance_pool.saturating_add(amount); }
|
||||
pub fn issue_policy(
|
||||
&mut self, asset_id: Hash, insured: Address, insurer: Address,
|
||||
insurance_type: InsuranceType, coverage_amount: u128, premium_rate_bps: u16,
|
||||
duration_secs: u64, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCInsuranceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCInsuranceError::InvalidConstitutionalReceipt); }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(asset_id.as_bytes());
|
||||
data.extend_from_slice(insured.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let policy_id = Hash::sha3_384(&data);
|
||||
let policy = InsurancePolicy {
|
||||
policy_id, asset_id, insured: insured.clone(), insurer, insurance_type,
|
||||
coverage_amount, claimed_amount: 0, premium_rate_bps,
|
||||
start_time: timestamp.clone(),
|
||||
end_time: timestamp.add_secs(duration_secs),
|
||||
is_active: true, constitutional_receipt, created_at: timestamp.clone(),
|
||||
};
|
||||
self.policies.insert(policy_id, policy);
|
||||
self.pending_events.push(InsuranceProtocolEvent::PolicyIssued {
|
||||
policy_id, asset_id, insured, coverage: coverage_amount, timestamp,
|
||||
});
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(policy_id)
|
||||
}
|
||||
pub fn submit_claim(
|
||||
&mut self, policy_id: Hash, claimant: Address, claim_amount: u128,
|
||||
claim_reason: String, evidence_hash: Hash, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCInsuranceError> {
|
||||
let policy = self.policies.get(&policy_id).ok_or(ACCInsuranceError::PolicyNotFound(policy_id))?;
|
||||
if policy.is_expired() { return Err(ACCInsuranceError::PolicyExpired(policy_id)); }
|
||||
if claim_amount > policy.remaining_coverage() {
|
||||
return Err(ACCInsuranceError::ClaimExceedsCoverage { coverage: policy.remaining_coverage(), claim: claim_amount });
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(policy_id.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let claim_id = Hash::sha3_384(&data);
|
||||
let claim = InsuranceClaim {
|
||||
claim_id, policy_id, claimant, claim_amount, claim_reason,
|
||||
evidence_hash, status: ClaimStatus::Pending,
|
||||
submitted_at: timestamp.clone(), processed_at: None, constitutional_receipt,
|
||||
};
|
||||
self.claims.insert(claim_id, claim);
|
||||
self.pending_events.push(InsuranceProtocolEvent::ClaimSubmitted { claim_id, policy_id, amount: claim_amount, timestamp });
|
||||
Ok(claim_id)
|
||||
}
|
||||
pub fn pay_claim(
|
||||
&mut self, claim_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<u128, ACCInsuranceError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCInsuranceError::InvalidConstitutionalReceipt); }
|
||||
let claim = self.claims.get_mut(&claim_id).ok_or(ACCInsuranceError::PolicyNotFound(claim_id))?;
|
||||
if claim.status != ClaimStatus::Pending && claim.status != ClaimStatus::UnderReview {
|
||||
return Err(ACCInsuranceError::ClaimAlreadyProcessed(claim_id));
|
||||
}
|
||||
let amount = claim.claim_amount;
|
||||
let policy_id = claim.policy_id;
|
||||
claim.status = ClaimStatus::Paid;
|
||||
claim.processed_at = Some(timestamp.clone());
|
||||
if let Some(policy) = self.policies.get_mut(&policy_id) {
|
||||
policy.claimed_amount = policy.claimed_amount.saturating_add(amount);
|
||||
}
|
||||
self.insurance_pool = self.insurance_pool.saturating_sub(amount);
|
||||
self.pending_events.push(InsuranceProtocolEvent::ClaimPaid { claim_id, amount, timestamp, constitutional_receipt });
|
||||
Ok(amount)
|
||||
}
|
||||
pub fn get_policy(&self, id: &Hash) -> Option<&InsurancePolicy> { self.policies.get(id) }
|
||||
pub fn get_claim(&self, id: &Hash) -> Option<&InsuranceClaim> { self.claims.get(id) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<InsuranceProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,119 +1,119 @@
|
|||
//! acc_redemption - NAC 原生协议实现
|
||||
//! 从 acc_remaining_protocols.rs 提取
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCRedemptionError {
|
||||
RedemptionNotFound(Hash),
|
||||
InsufficientRedemptionFund { available: u128, requested: u128 },
|
||||
RedemptionWindowClosed,
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
RedemptionAlreadyProcessed(Hash),
|
||||
}
|
||||
impl std::fmt::Display for ACCRedemptionError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::RedemptionNotFound(h) => write!(f, "赎回请求不存在: {}", h.to_hex()),
|
||||
Self::InsufficientRedemptionFund { available, requested } => write!(f, "赎回资金不足: 可用 {},请求 {}", available, requested),
|
||||
Self::RedemptionWindowClosed => write!(f, "赎回窗口已关闭"),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::RedemptionAlreadyProcessed(h) => write!(f, "赎回请求已处理: {}", h.to_hex()),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCRedemptionError {
|
||||
RedemptionNotFound(Hash),
|
||||
InsufficientRedemptionFund { available: u128, requested: u128 },
|
||||
RedemptionWindowClosed,
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
RedemptionAlreadyProcessed(Hash),
|
||||
}
|
||||
impl std::fmt::Display for ACCRedemptionError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::RedemptionNotFound(h) => write!(f, "赎回请求不存在: {}", h.to_hex()),
|
||||
Self::InsufficientRedemptionFund { available, requested } => write!(f, "赎回资金不足: 可用 {},请求 {}", available, requested),
|
||||
Self::RedemptionWindowClosed => write!(f, "赎回窗口已关闭"),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::RedemptionAlreadyProcessed(h) => write!(f, "赎回请求已处理: {}", h.to_hex()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RedemptionStatus { Pending, Processing, Completed, Rejected, Cancelled }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RedemptionStatus { Pending, Processing, Completed, Rejected, Cancelled }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RedemptionRequest {
|
||||
pub redemption_id: Hash,
|
||||
pub asset_id: Hash,
|
||||
pub redeemer: Address,
|
||||
pub amount: u128,
|
||||
pub redemption_price_xtzh: u128,
|
||||
pub total_redemption_xtzh: u128,
|
||||
pub status: RedemptionStatus,
|
||||
pub requested_at: Timestamp,
|
||||
pub processed_at: Option<Timestamp>,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub rejection_reason: Option<String>,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RedemptionRequest {
|
||||
pub redemption_id: Hash,
|
||||
pub asset_id: Hash,
|
||||
pub redeemer: Address,
|
||||
pub amount: u128,
|
||||
pub redemption_price_xtzh: u128,
|
||||
pub total_redemption_xtzh: u128,
|
||||
pub status: RedemptionStatus,
|
||||
pub requested_at: Timestamp,
|
||||
pub processed_at: Option<Timestamp>,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub rejection_reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RedemptionProtocolEvent {
|
||||
RedemptionRequested { redemption_id: Hash, asset_id: Hash, redeemer: Address, amount: u128, timestamp: Timestamp },
|
||||
RedemptionCompleted { redemption_id: Hash, total_xtzh: u128, timestamp: Timestamp },
|
||||
RedemptionRejected { redemption_id: Hash, reason: String, timestamp: Timestamp },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RedemptionProtocolEvent {
|
||||
RedemptionRequested { redemption_id: Hash, asset_id: Hash, redeemer: Address, amount: u128, timestamp: Timestamp },
|
||||
RedemptionCompleted { redemption_id: Hash, total_xtzh: u128, timestamp: Timestamp },
|
||||
RedemptionRejected { redemption_id: Hash, reason: String, timestamp: Timestamp },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCRedemptionProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub requests: HashMap<Hash, RedemptionRequest>,
|
||||
pub redemption_fund: HashMap<Hash, u128>,
|
||||
pub redemption_window_open: bool,
|
||||
pub pending_events: Vec<RedemptionProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCRedemptionProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub requests: HashMap<Hash, RedemptionRequest>,
|
||||
pub redemption_fund: HashMap<Hash, u128>,
|
||||
pub redemption_window_open: bool,
|
||||
pub pending_events: Vec<RedemptionProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCRedemptionProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCRedemptionProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Redemption".to_string(),
|
||||
requests: HashMap::new(), redemption_fund: HashMap::new(),
|
||||
redemption_window_open: true, pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(), updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
impl ACCRedemptionProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCRedemptionProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Redemption".to_string(),
|
||||
requests: HashMap::new(), redemption_fund: HashMap::new(),
|
||||
redemption_window_open: true, pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(), updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
pub fn fund_redemption_pool(&mut self, asset_id: Hash, amount_xtzh: u128, constitutional_receipt: Hash) -> Result<(), ACCRedemptionError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); }
|
||||
*self.redemption_fund.entry(asset_id).or_insert(0) += amount_xtzh;
|
||||
Ok(())
|
||||
}
|
||||
pub fn request_redemption(
|
||||
&mut self, asset_id: Hash, redeemer: Address, amount: u128,
|
||||
redemption_price_xtzh: u128, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCRedemptionError> {
|
||||
if !self.redemption_window_open { return Err(ACCRedemptionError::RedemptionWindowClosed); }
|
||||
let total = amount.saturating_mul(redemption_price_xtzh);
|
||||
let available = self.redemption_fund.get(&asset_id).copied().unwrap_or(0);
|
||||
if available < total { return Err(ACCRedemptionError::InsufficientRedemptionFund { available, requested: total }); }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(asset_id.as_bytes());
|
||||
data.extend_from_slice(redeemer.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let redemption_id = Hash::sha3_384(&data);
|
||||
let request = RedemptionRequest {
|
||||
redemption_id, asset_id, redeemer: redeemer.clone(), amount,
|
||||
redemption_price_xtzh, total_redemption_xtzh: total,
|
||||
status: RedemptionStatus::Pending,
|
||||
requested_at: timestamp.clone(), processed_at: None,
|
||||
constitutional_receipt, rejection_reason: None,
|
||||
};
|
||||
self.requests.insert(redemption_id, request);
|
||||
self.pending_events.push(RedemptionProtocolEvent::RedemptionRequested { redemption_id, asset_id, redeemer, amount, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(redemption_id)
|
||||
}
|
||||
pub fn complete_redemption(&mut self, redemption_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp) -> Result<u128, ACCRedemptionError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); }
|
||||
let request = self.requests.get_mut(&redemption_id).ok_or(ACCRedemptionError::RedemptionNotFound(redemption_id))?;
|
||||
if request.status != RedemptionStatus::Pending { return Err(ACCRedemptionError::RedemptionAlreadyProcessed(redemption_id)); }
|
||||
let total = request.total_redemption_xtzh;
|
||||
let asset_id = request.asset_id;
|
||||
if let Some(fund) = self.redemption_fund.get_mut(&asset_id) { *fund = fund.saturating_sub(total); }
|
||||
request.status = RedemptionStatus::Completed;
|
||||
request.processed_at = Some(timestamp.clone());
|
||||
self.pending_events.push(RedemptionProtocolEvent::RedemptionCompleted { redemption_id, total_xtzh: total, timestamp });
|
||||
Ok(total)
|
||||
}
|
||||
pub fn get_request(&self, id: &Hash) -> Option<&RedemptionRequest> { self.requests.get(id) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<RedemptionProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
pub fn fund_redemption_pool(&mut self, asset_id: Hash, amount_xtzh: u128, constitutional_receipt: Hash) -> Result<(), ACCRedemptionError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); }
|
||||
*self.redemption_fund.entry(asset_id).or_insert(0) += amount_xtzh;
|
||||
Ok(())
|
||||
}
|
||||
pub fn request_redemption(
|
||||
&mut self, asset_id: Hash, redeemer: Address, amount: u128,
|
||||
redemption_price_xtzh: u128, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCRedemptionError> {
|
||||
if !self.redemption_window_open { return Err(ACCRedemptionError::RedemptionWindowClosed); }
|
||||
let total = amount.saturating_mul(redemption_price_xtzh);
|
||||
let available = self.redemption_fund.get(&asset_id).copied().unwrap_or(0);
|
||||
if available < total { return Err(ACCRedemptionError::InsufficientRedemptionFund { available, requested: total }); }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(asset_id.as_bytes());
|
||||
data.extend_from_slice(redeemer.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let redemption_id = Hash::sha3_384(&data);
|
||||
let request = RedemptionRequest {
|
||||
redemption_id, asset_id, redeemer: redeemer.clone(), amount,
|
||||
redemption_price_xtzh, total_redemption_xtzh: total,
|
||||
status: RedemptionStatus::Pending,
|
||||
requested_at: timestamp.clone(), processed_at: None,
|
||||
constitutional_receipt, rejection_reason: None,
|
||||
};
|
||||
self.requests.insert(redemption_id, request);
|
||||
self.pending_events.push(RedemptionProtocolEvent::RedemptionRequested { redemption_id, asset_id, redeemer, amount, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(redemption_id)
|
||||
}
|
||||
pub fn complete_redemption(&mut self, redemption_id: Hash, constitutional_receipt: Hash, timestamp: Timestamp) -> Result<u128, ACCRedemptionError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCRedemptionError::InvalidConstitutionalReceipt); }
|
||||
let request = self.requests.get_mut(&redemption_id).ok_or(ACCRedemptionError::RedemptionNotFound(redemption_id))?;
|
||||
if request.status != RedemptionStatus::Pending { return Err(ACCRedemptionError::RedemptionAlreadyProcessed(redemption_id)); }
|
||||
let total = request.total_redemption_xtzh;
|
||||
let asset_id = request.asset_id;
|
||||
if let Some(fund) = self.redemption_fund.get_mut(&asset_id) { *fund = fund.saturating_sub(total); }
|
||||
request.status = RedemptionStatus::Completed;
|
||||
request.processed_at = Some(timestamp.clone());
|
||||
self.pending_events.push(RedemptionProtocolEvent::RedemptionCompleted { redemption_id, total_xtzh: total, timestamp });
|
||||
Ok(total)
|
||||
}
|
||||
pub fn get_request(&self, id: &Hash) -> Option<&RedemptionRequest> { self.requests.get(id) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<RedemptionProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,112 +1,112 @@
|
|||
//! acc_reserve - NAC 原生协议实现
|
||||
//! 从 acc_remaining_protocols.rs 提取
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCReserveError {
|
||||
ReserveNotFound(String),
|
||||
InsufficientReserve { asset: String, available: u128, requested: u128 },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
ReserveRatioViolation { required: u8, actual: u8 },
|
||||
}
|
||||
impl std::fmt::Display for ACCReserveError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ReserveNotFound(s) => write!(f, "储备资产不存在: {}", s),
|
||||
Self::InsufficientReserve { asset, available, requested } => write!(f, "储备不足 {}: 可用 {},请求 {}", asset, available, requested),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::ReserveRatioViolation { required, actual } => write!(f, "储备率违规: 要求 {}%,实际 {}%", required, actual),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCReserveError {
|
||||
ReserveNotFound(String),
|
||||
InsufficientReserve { asset: String, available: u128, requested: u128 },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
ReserveRatioViolation { required: u8, actual: u8 },
|
||||
}
|
||||
impl std::fmt::Display for ACCReserveError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ReserveNotFound(s) => write!(f, "储备资产不存在: {}", s),
|
||||
Self::InsufficientReserve { asset, available, requested } => write!(f, "储备不足 {}: 可用 {},请求 {}", asset, available, requested),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::ReserveRatioViolation { required, actual } => write!(f, "储备率违规: 要求 {}%,实际 {}%", required, actual),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ReserveEntry {
|
||||
pub asset_symbol: String,
|
||||
pub amount: u128,
|
||||
pub custodian: Address,
|
||||
pub last_audited: Timestamp,
|
||||
pub audit_hash: Hash,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ReserveEntry {
|
||||
pub asset_symbol: String,
|
||||
pub amount: u128,
|
||||
pub custodian: Address,
|
||||
pub last_audited: Timestamp,
|
||||
pub audit_hash: Hash,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ReserveProtocolEvent {
|
||||
ReserveDeposited { asset: String, amount: u128, custodian: Address, timestamp: Timestamp },
|
||||
ReserveWithdrawn { asset: String, amount: u128, recipient: Address, constitutional_receipt: Hash, timestamp: Timestamp },
|
||||
ReserveAudited { asset: String, audit_hash: Hash, timestamp: Timestamp },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ReserveProtocolEvent {
|
||||
ReserveDeposited { asset: String, amount: u128, custodian: Address, timestamp: Timestamp },
|
||||
ReserveWithdrawn { asset: String, amount: u128, recipient: Address, constitutional_receipt: Hash, timestamp: Timestamp },
|
||||
ReserveAudited { asset: String, audit_hash: Hash, timestamp: Timestamp },
|
||||
}
|
||||
|
||||
/// ACC-Reserve 储备协议
|
||||
/// UID: nac.acc.ACCReserveProtocol.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCReserveProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub reserves: HashMap<String, ReserveEntry>,
|
||||
/// 最低储备率(百分比)
|
||||
pub min_reserve_ratio: u8,
|
||||
pub pending_events: Vec<ReserveProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
/// ACC-Reserve 储备协议
|
||||
/// UID: nac.acc.ACCReserveProtocol.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCReserveProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub reserves: HashMap<String, ReserveEntry>,
|
||||
/// 最低储备率(百分比)
|
||||
pub min_reserve_ratio: u8,
|
||||
pub pending_events: Vec<ReserveProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCReserveProtocol {
|
||||
pub fn new(min_reserve_ratio: u8) -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCReserveProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Reserve".to_string(),
|
||||
reserves: HashMap::new(),
|
||||
min_reserve_ratio,
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
impl ACCReserveProtocol {
|
||||
pub fn new(min_reserve_ratio: u8) -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCReserveProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-Reserve".to_string(),
|
||||
reserves: HashMap::new(),
|
||||
min_reserve_ratio,
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
pub fn deposit(
|
||||
&mut self, asset_symbol: String, amount: u128, custodian: Address,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCReserveError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCReserveError::InvalidConstitutionalReceipt); }
|
||||
let entry = self.reserves.entry(asset_symbol.clone()).or_insert(ReserveEntry {
|
||||
asset_symbol: asset_symbol.clone(), amount: 0,
|
||||
custodian: custodian.clone(), last_audited: timestamp.clone(),
|
||||
audit_hash: Hash::zero(),
|
||||
});
|
||||
entry.amount = entry.amount.saturating_add(amount);
|
||||
entry.custodian = custodian.clone();
|
||||
self.pending_events.push(ReserveProtocolEvent::ReserveDeposited { asset: asset_symbol, amount, custodian, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn withdraw(
|
||||
&mut self, asset_symbol: String, amount: u128, recipient: Address,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCReserveError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCReserveError::InvalidConstitutionalReceipt); }
|
||||
let entry = self.reserves.get_mut(&asset_symbol)
|
||||
.ok_or_else(|| ACCReserveError::ReserveNotFound(asset_symbol.clone()))?;
|
||||
if entry.amount < amount {
|
||||
return Err(ACCReserveError::InsufficientReserve { asset: asset_symbol.clone(), available: entry.amount, requested: amount });
|
||||
}
|
||||
entry.amount -= amount;
|
||||
self.pending_events.push(ReserveProtocolEvent::ReserveWithdrawn { asset: asset_symbol, amount, recipient, constitutional_receipt, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn audit(
|
||||
&mut self, asset_symbol: String, audit_hash: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCReserveError> {
|
||||
let entry = self.reserves.get_mut(&asset_symbol)
|
||||
.ok_or_else(|| ACCReserveError::ReserveNotFound(asset_symbol.clone()))?;
|
||||
entry.last_audited = timestamp.clone();
|
||||
entry.audit_hash = audit_hash;
|
||||
self.pending_events.push(ReserveProtocolEvent::ReserveAudited { asset: asset_symbol, audit_hash, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
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<ReserveProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
pub fn deposit(
|
||||
&mut self, asset_symbol: String, amount: u128, custodian: Address,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCReserveError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCReserveError::InvalidConstitutionalReceipt); }
|
||||
let entry = self.reserves.entry(asset_symbol.clone()).or_insert(ReserveEntry {
|
||||
asset_symbol: asset_symbol.clone(), amount: 0,
|
||||
custodian: custodian.clone(), last_audited: timestamp.clone(),
|
||||
audit_hash: Hash::zero(),
|
||||
});
|
||||
entry.amount = entry.amount.saturating_add(amount);
|
||||
entry.custodian = custodian.clone();
|
||||
self.pending_events.push(ReserveProtocolEvent::ReserveDeposited { asset: asset_symbol, amount, custodian, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn withdraw(
|
||||
&mut self, asset_symbol: String, amount: u128, recipient: Address,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCReserveError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCReserveError::InvalidConstitutionalReceipt); }
|
||||
let entry = self.reserves.get_mut(&asset_symbol)
|
||||
.ok_or_else(|| ACCReserveError::ReserveNotFound(asset_symbol.clone()))?;
|
||||
if entry.amount < amount {
|
||||
return Err(ACCReserveError::InsufficientReserve { asset: asset_symbol.clone(), available: entry.amount, requested: amount });
|
||||
}
|
||||
entry.amount -= amount;
|
||||
self.pending_events.push(ReserveProtocolEvent::ReserveWithdrawn { asset: asset_symbol, amount, recipient, constitutional_receipt, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn audit(
|
||||
&mut self, asset_symbol: String, audit_hash: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCReserveError> {
|
||||
let entry = self.reserves.get_mut(&asset_symbol)
|
||||
.ok_or_else(|| ACCReserveError::ReserveNotFound(asset_symbol.clone()))?;
|
||||
entry.last_audited = timestamp.clone();
|
||||
entry.audit_hash = audit_hash;
|
||||
self.pending_events.push(ReserveProtocolEvent::ReserveAudited { asset: asset_symbol, audit_hash, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
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<ReserveProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,177 +1,177 @@
|
|||
//! acc_rwa - NAC 原生协议实现
|
||||
//! 从 acc_remaining_protocols.rs 提取
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCRWAError {
|
||||
AssetNotFound(Hash),
|
||||
AssetAlreadyRegistered(Hash),
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
ComplianceCheckFailed(String),
|
||||
ValuationExpired(Hash),
|
||||
AssetFrozen(Hash),
|
||||
}
|
||||
impl std::fmt::Display for ACCRWAError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::AssetNotFound(h) => write!(f, "RWA 资产不存在: {}", h.to_hex()),
|
||||
Self::AssetAlreadyRegistered(h) => write!(f, "RWA 资产已注册: {}", h.to_hex()),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::ComplianceCheckFailed(msg) => write!(f, "合规检查失败: {}", msg),
|
||||
Self::ValuationExpired(h) => write!(f, "估值已过期: {}", h.to_hex()),
|
||||
Self::AssetFrozen(h) => write!(f, "资产已冻结: {}", h.to_hex()),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCRWAError {
|
||||
AssetNotFound(Hash),
|
||||
AssetAlreadyRegistered(Hash),
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
ComplianceCheckFailed(String),
|
||||
ValuationExpired(Hash),
|
||||
AssetFrozen(Hash),
|
||||
}
|
||||
impl std::fmt::Display for ACCRWAError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::AssetNotFound(h) => write!(f, "RWA 资产不存在: {}", h.to_hex()),
|
||||
Self::AssetAlreadyRegistered(h) => write!(f, "RWA 资产已注册: {}", h.to_hex()),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::ComplianceCheckFailed(msg) => write!(f, "合规检查失败: {}", msg),
|
||||
Self::ValuationExpired(h) => write!(f, "估值已过期: {}", h.to_hex()),
|
||||
Self::AssetFrozen(h) => write!(f, "资产已冻结: {}", h.to_hex()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RWAAssetType {
|
||||
RealEstate,
|
||||
CorporateBond,
|
||||
GovernmentBond,
|
||||
Commodity,
|
||||
PrivateEquity,
|
||||
Infrastructure,
|
||||
IntellectualProperty,
|
||||
NaturalResource,
|
||||
Other,
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RWAAssetType {
|
||||
RealEstate,
|
||||
CorporateBond,
|
||||
GovernmentBond,
|
||||
Commodity,
|
||||
PrivateEquity,
|
||||
Infrastructure,
|
||||
IntellectualProperty,
|
||||
NaturalResource,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RWAAssetStatus { Pending, Active, Frozen, Redeemed, Delisted }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum RWAAssetStatus { Pending, Active, Frozen, Redeemed, Delisted }
|
||||
|
||||
/// RWA 资产记录
|
||||
/// UID: nac.acc.RWAAssetRecord.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RWAAssetRecord {
|
||||
pub asset_id: Hash,
|
||||
pub gnacs_code: String,
|
||||
pub asset_type: RWAAssetType,
|
||||
pub owner: Address,
|
||||
pub issuer: Address,
|
||||
pub total_supply: u128,
|
||||
pub current_valuation_xtzh: u128,
|
||||
pub jurisdiction: String,
|
||||
pub status: RWAAssetStatus,
|
||||
/// 法律文件哈希(SHA3-384)
|
||||
pub legal_document_hash: Hash,
|
||||
/// AI 合规评分(0-100)
|
||||
pub ai_compliance_score: u8,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub registered_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
/// RWA 资产记录
|
||||
/// UID: nac.acc.RWAAssetRecord.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RWAAssetRecord {
|
||||
pub asset_id: Hash,
|
||||
pub gnacs_code: String,
|
||||
pub asset_type: RWAAssetType,
|
||||
pub owner: Address,
|
||||
pub issuer: Address,
|
||||
pub total_supply: u128,
|
||||
pub current_valuation_xtzh: u128,
|
||||
pub jurisdiction: String,
|
||||
pub status: RWAAssetStatus,
|
||||
/// 法律文件哈希(SHA3-384)
|
||||
pub legal_document_hash: Hash,
|
||||
/// AI 合规评分(0-100)
|
||||
pub ai_compliance_score: u8,
|
||||
pub constitutional_receipt: Hash,
|
||||
pub registered_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RWAProtocolEvent {
|
||||
AssetRegistered { asset_id: Hash, gnacs_code: String, owner: Address, valuation: u128, timestamp: Timestamp },
|
||||
AssetTransferred { asset_id: Hash, from: Address, to: Address, amount: u128, timestamp: Timestamp },
|
||||
AssetFrozen { asset_id: Hash, reason: String, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
AssetUnfrozen { asset_id: Hash, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
ValuationUpdated { asset_id: Hash, old_value: u128, new_value: u128, timestamp: Timestamp },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RWAProtocolEvent {
|
||||
AssetRegistered { asset_id: Hash, gnacs_code: String, owner: Address, valuation: u128, timestamp: Timestamp },
|
||||
AssetTransferred { asset_id: Hash, from: Address, to: Address, amount: u128, timestamp: Timestamp },
|
||||
AssetFrozen { asset_id: Hash, reason: String, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
AssetUnfrozen { asset_id: Hash, timestamp: Timestamp, constitutional_receipt: Hash },
|
||||
ValuationUpdated { asset_id: Hash, old_value: u128, new_value: u128, timestamp: Timestamp },
|
||||
}
|
||||
|
||||
/// ACC-RWA 真实世界资产协议
|
||||
/// UID: nac.acc.ACCRWAProtocol.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCRWAProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub assets: HashMap<Hash, RWAAssetRecord>,
|
||||
/// 持仓(asset_id -> (address -> amount))
|
||||
pub holdings: HashMap<Hash, HashMap<Address, u128>>,
|
||||
pub pending_events: Vec<RWAProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
/// ACC-RWA 真实世界资产协议
|
||||
/// UID: nac.acc.ACCRWAProtocol.v1
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ACCRWAProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub assets: HashMap<Hash, RWAAssetRecord>,
|
||||
/// 持仓(asset_id -> (address -> amount))
|
||||
pub holdings: HashMap<Hash, HashMap<Address, u128>>,
|
||||
pub pending_events: Vec<RWAProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl ACCRWAProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCRWAProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-RWA".to_string(),
|
||||
assets: HashMap::new(),
|
||||
holdings: HashMap::new(),
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
impl ACCRWAProtocol {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.ACCRWAProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-RWA".to_string(),
|
||||
assets: HashMap::new(),
|
||||
holdings: HashMap::new(),
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
pub fn register_asset(
|
||||
&mut self, gnacs_code: String, asset_type: RWAAssetType, owner: Address, issuer: Address,
|
||||
total_supply: u128, initial_valuation_xtzh: u128, jurisdiction: String,
|
||||
legal_document_hash: Hash, ai_compliance_score: u8,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCRWAError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCRWAError::InvalidConstitutionalReceipt); }
|
||||
if ai_compliance_score < 60 {
|
||||
return Err(ACCRWAError::ComplianceCheckFailed(format!("AI 合规评分不足: {}/100", ai_compliance_score)));
|
||||
}
|
||||
pub fn register_asset(
|
||||
&mut self, gnacs_code: String, asset_type: RWAAssetType, owner: Address, issuer: Address,
|
||||
total_supply: u128, initial_valuation_xtzh: u128, jurisdiction: String,
|
||||
legal_document_hash: Hash, ai_compliance_score: u8,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<Hash, ACCRWAError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCRWAError::InvalidConstitutionalReceipt); }
|
||||
if ai_compliance_score < 60 {
|
||||
return Err(ACCRWAError::ComplianceCheckFailed(format!("AI 合规评分不足: {}/100", ai_compliance_score)));
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(gnacs_code.as_bytes());
|
||||
data.extend_from_slice(owner.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let asset_id = Hash::sha3_384(&data);
|
||||
if self.assets.contains_key(&asset_id) { return Err(ACCRWAError::AssetAlreadyRegistered(asset_id)); }
|
||||
let record = RWAAssetRecord {
|
||||
asset_id, gnacs_code: gnacs_code.clone(), asset_type, owner: owner.clone(), issuer,
|
||||
total_supply, current_valuation_xtzh: initial_valuation_xtzh,
|
||||
jurisdiction, status: RWAAssetStatus::Active,
|
||||
legal_document_hash, ai_compliance_score, constitutional_receipt,
|
||||
registered_at: timestamp.clone(), updated_at: timestamp.clone(),
|
||||
};
|
||||
let mut asset_holdings = HashMap::new();
|
||||
asset_holdings.insert(owner.clone(), total_supply);
|
||||
self.holdings.insert(asset_id, asset_holdings);
|
||||
self.assets.insert(asset_id, record);
|
||||
self.pending_events.push(RWAProtocolEvent::AssetRegistered {
|
||||
asset_id, gnacs_code, owner, valuation: initial_valuation_xtzh, timestamp,
|
||||
});
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(asset_id)
|
||||
}
|
||||
pub fn transfer_asset(
|
||||
&mut self, asset_id: Hash, from: Address, to: Address, amount: u128, timestamp: Timestamp,
|
||||
) -> Result<(), ACCRWAError> {
|
||||
let asset = self.assets.get(&asset_id).ok_or(ACCRWAError::AssetNotFound(asset_id))?;
|
||||
if asset.status == RWAAssetStatus::Frozen { return Err(ACCRWAError::AssetFrozen(asset_id)); }
|
||||
let holdings = self.holdings.get_mut(&asset_id).ok_or(ACCRWAError::AssetNotFound(asset_id))?;
|
||||
let from_balance = holdings.get(&from).copied().unwrap_or(0);
|
||||
if from_balance < amount {
|
||||
return Err(ACCRWAError::Unauthorized(from.clone()));
|
||||
}
|
||||
*holdings.get_mut(&from).unwrap() -= amount;
|
||||
*holdings.entry(to.clone()).or_insert(0) += amount;
|
||||
self.pending_events.push(RWAProtocolEvent::AssetTransferred { asset_id, from, to, amount, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn freeze_asset(
|
||||
&mut self, asset_id: Hash, reason: String, 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(asset_id))?;
|
||||
asset.status = RWAAssetStatus::Frozen;
|
||||
asset.updated_at = timestamp.clone();
|
||||
self.pending_events.push(RWAProtocolEvent::AssetFrozen { asset_id, reason, timestamp, constitutional_receipt });
|
||||
Ok(())
|
||||
}
|
||||
pub fn update_valuation(
|
||||
&mut self, asset_id: Hash, new_valuation: u128, 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(asset_id))?;
|
||||
let old_value = asset.current_valuation_xtzh;
|
||||
asset.current_valuation_xtzh = new_valuation;
|
||||
asset.updated_at = timestamp.clone();
|
||||
self.pending_events.push(RWAProtocolEvent::ValuationUpdated { asset_id, old_value, new_value: new_valuation, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn get_asset(&self, id: &Hash) -> Option<&RWAAssetRecord> { self.assets.get(id) }
|
||||
pub fn balance_of(&self, asset_id: &Hash, holder: &Address) -> u128 {
|
||||
self.holdings.get(asset_id).and_then(|h| h.get(holder)).copied().unwrap_or(0)
|
||||
}
|
||||
pub fn drain_pending_events(&mut self) -> Vec<RWAProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(gnacs_code.as_bytes());
|
||||
data.extend_from_slice(owner.as_bytes());
|
||||
data.extend_from_slice(×tamp.as_secs().to_be_bytes());
|
||||
let asset_id = Hash::sha3_384(&data);
|
||||
if self.assets.contains_key(&asset_id) { return Err(ACCRWAError::AssetAlreadyRegistered(asset_id)); }
|
||||
let record = RWAAssetRecord {
|
||||
asset_id, gnacs_code: gnacs_code.clone(), asset_type, owner: owner.clone(), issuer,
|
||||
total_supply, current_valuation_xtzh: initial_valuation_xtzh,
|
||||
jurisdiction, status: RWAAssetStatus::Active,
|
||||
legal_document_hash, ai_compliance_score, constitutional_receipt,
|
||||
registered_at: timestamp.clone(), updated_at: timestamp.clone(),
|
||||
};
|
||||
let mut asset_holdings = HashMap::new();
|
||||
asset_holdings.insert(owner.clone(), total_supply);
|
||||
self.holdings.insert(asset_id, asset_holdings);
|
||||
self.assets.insert(asset_id, record);
|
||||
self.pending_events.push(RWAProtocolEvent::AssetRegistered {
|
||||
asset_id, gnacs_code, owner, valuation: initial_valuation_xtzh, timestamp,
|
||||
});
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(asset_id)
|
||||
}
|
||||
pub fn transfer_asset(
|
||||
&mut self, asset_id: Hash, from: Address, to: Address, amount: u128, timestamp: Timestamp,
|
||||
) -> Result<(), ACCRWAError> {
|
||||
let asset = self.assets.get(&asset_id).ok_or(ACCRWAError::AssetNotFound(asset_id))?;
|
||||
if asset.status == RWAAssetStatus::Frozen { return Err(ACCRWAError::AssetFrozen(asset_id)); }
|
||||
let holdings = self.holdings.get_mut(&asset_id).ok_or(ACCRWAError::AssetNotFound(asset_id))?;
|
||||
let from_balance = holdings.get(&from).copied().unwrap_or(0);
|
||||
if from_balance < amount {
|
||||
return Err(ACCRWAError::Unauthorized(from.clone()));
|
||||
}
|
||||
*holdings.get_mut(&from).unwrap() -= amount;
|
||||
*holdings.entry(to.clone()).or_insert(0) += amount;
|
||||
self.pending_events.push(RWAProtocolEvent::AssetTransferred { asset_id, from, to, amount, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn freeze_asset(
|
||||
&mut self, asset_id: Hash, reason: String, 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(asset_id))?;
|
||||
asset.status = RWAAssetStatus::Frozen;
|
||||
asset.updated_at = timestamp.clone();
|
||||
self.pending_events.push(RWAProtocolEvent::AssetFrozen { asset_id, reason, timestamp, constitutional_receipt });
|
||||
Ok(())
|
||||
}
|
||||
pub fn update_valuation(
|
||||
&mut self, asset_id: Hash, new_valuation: u128, 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(asset_id))?;
|
||||
let old_value = asset.current_valuation_xtzh;
|
||||
asset.current_valuation_xtzh = new_valuation;
|
||||
asset.updated_at = timestamp.clone();
|
||||
self.pending_events.push(RWAProtocolEvent::ValuationUpdated { asset_id, old_value, new_value: new_valuation, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn get_asset(&self, id: &Hash) -> Option<&RWAAssetRecord> { self.assets.get(id) }
|
||||
pub fn balance_of(&self, asset_id: &Hash, holder: &Address) -> u128 {
|
||||
self.holdings.get(asset_id).and_then(|h| h.get(holder)).copied().unwrap_or(0)
|
||||
}
|
||||
pub fn drain_pending_events(&mut self) -> Vec<RWAProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,172 +1,172 @@
|
|||
//! acc_xtzh - NAC 原生协议实现
|
||||
//! 从 acc_remaining_protocols.rs 提取
|
||||
use crate::primitives::{Address, Hash, Timestamp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCXTZHError {
|
||||
InsufficientBalance { holder: Address, available: u128, requested: u128 },
|
||||
InsufficientReserve { required: u128, available: u128 },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
SDRPegViolation { current_rate: u128, min_rate: u128, max_rate: u128 },
|
||||
GoldReserveInsufficient { required_ratio: u8, actual_ratio: u8 },
|
||||
}
|
||||
impl std::fmt::Display for ACCXTZHError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InsufficientBalance { holder, available, requested } => write!(f, "余额不足 {}: 可用 {},请求 {}", holder.to_hex(), available, requested),
|
||||
Self::InsufficientReserve { required, available } => write!(f, "储备不足: 需要 {},可用 {}", required, available),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::SDRPegViolation { current_rate, min_rate, max_rate } => write!(f, "SDR 锚定偏离: 当前 {},允许范围 [{}, {}]", current_rate, min_rate, max_rate),
|
||||
Self::GoldReserveInsufficient { required_ratio, actual_ratio } => write!(f, "黄金储备不足: 要求 {}%,实际 {}%", required_ratio, actual_ratio),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ACCXTZHError {
|
||||
InsufficientBalance { holder: Address, available: u128, requested: u128 },
|
||||
InsufficientReserve { required: u128, available: u128 },
|
||||
InvalidConstitutionalReceipt,
|
||||
Unauthorized(Address),
|
||||
SDRPegViolation { current_rate: u128, min_rate: u128, max_rate: u128 },
|
||||
GoldReserveInsufficient { required_ratio: u8, actual_ratio: u8 },
|
||||
}
|
||||
impl std::fmt::Display for ACCXTZHError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InsufficientBalance { holder, available, requested } => write!(f, "余额不足 {}: 可用 {},请求 {}", holder.to_hex(), available, requested),
|
||||
Self::InsufficientReserve { required, available } => write!(f, "储备不足: 需要 {},可用 {}", required, available),
|
||||
Self::InvalidConstitutionalReceipt => write!(f, "宪法收据无效"),
|
||||
Self::Unauthorized(a) => write!(f, "未授权: {}", a.to_hex()),
|
||||
Self::SDRPegViolation { current_rate, min_rate, max_rate } => write!(f, "SDR 锚定偏离: 当前 {},允许范围 [{}, {}]", current_rate, min_rate, max_rate),
|
||||
Self::GoldReserveInsufficient { required_ratio, actual_ratio } => write!(f, "黄金储备不足: 要求 {}%,实际 {}%", required_ratio, actual_ratio),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ReserveAssetType { Gold, USD, EUR, GBP, JPY, CNY, NACNative }
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ReserveAssetType { Gold, USD, EUR, GBP, JPY, CNY, NACNative }
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ReserveAsset {
|
||||
pub asset_type: ReserveAssetType,
|
||||
pub amount: u128,
|
||||
/// 权重(基点,10000=100%)
|
||||
pub weight_bps: u16,
|
||||
pub last_updated: Timestamp,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ReserveAsset {
|
||||
pub asset_type: ReserveAssetType,
|
||||
pub amount: u128,
|
||||
/// 权重(基点,10000=100%)
|
||||
pub weight_bps: u16,
|
||||
pub last_updated: Timestamp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum XTZHProtocolEvent {
|
||||
Minted { recipient: Address, amount: u128, constitutional_receipt: Hash, timestamp: Timestamp },
|
||||
Burned { holder: Address, amount: u128, constitutional_receipt: Hash, timestamp: Timestamp },
|
||||
Transferred { from: Address, to: Address, amount: u128, timestamp: Timestamp },
|
||||
ReserveRebalanced { old_gold_ratio: u8, new_gold_ratio: u8, timestamp: Timestamp },
|
||||
SDRRateUpdated { old_rate: u128, new_rate: u128, timestamp: Timestamp },
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum XTZHProtocolEvent {
|
||||
Minted { recipient: Address, amount: u128, constitutional_receipt: Hash, timestamp: Timestamp },
|
||||
Burned { holder: Address, amount: u128, constitutional_receipt: Hash, timestamp: Timestamp },
|
||||
Transferred { from: Address, to: Address, amount: u128, timestamp: Timestamp },
|
||||
ReserveRebalanced { old_gold_ratio: u8, new_gold_ratio: u8, timestamp: Timestamp },
|
||||
SDRRateUpdated { old_rate: u128, new_rate: u128, timestamp: Timestamp },
|
||||
}
|
||||
|
||||
/// XTZH 稳定币协议
|
||||
/// UID: nac.acc.XTZHStablecoinProtocol.v1
|
||||
/// SDR 锚定 + 黄金储备保障
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct XTZHStablecoinProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub total_supply: u128,
|
||||
/// 持仓(address -> 余额,精度18位)
|
||||
pub holdings: HashMap<Address, u128>,
|
||||
/// 储备资产
|
||||
pub reserve_assets: Vec<ReserveAsset>,
|
||||
/// SDR 锚定汇率(XTZH/SDR,精度18位,1 XTZH = 1 SDR)
|
||||
pub sdr_peg_rate: u128,
|
||||
/// SDR 汇率允许偏差(基点,默认200=2%)
|
||||
pub sdr_tolerance_bps: u16,
|
||||
/// 黄金储备最低比例(百分比,默认40)
|
||||
pub min_gold_reserve_ratio: u8,
|
||||
/// 当前黄金储备比例
|
||||
pub current_gold_reserve_ratio: u8,
|
||||
pub pending_events: Vec<XTZHProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
/// XTZH 稳定币协议
|
||||
/// UID: nac.acc.XTZHStablecoinProtocol.v1
|
||||
/// SDR 锚定 + 黄金储备保障
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct XTZHStablecoinProtocol {
|
||||
pub protocol_uid: String,
|
||||
pub lens_protocol_vector: String,
|
||||
pub total_supply: u128,
|
||||
/// 持仓(address -> 余额,精度18位)
|
||||
pub holdings: HashMap<Address, u128>,
|
||||
/// 储备资产
|
||||
pub reserve_assets: Vec<ReserveAsset>,
|
||||
/// SDR 锚定汇率(XTZH/SDR,精度18位,1 XTZH = 1 SDR)
|
||||
pub sdr_peg_rate: u128,
|
||||
/// SDR 汇率允许偏差(基点,默认200=2%)
|
||||
pub sdr_tolerance_bps: u16,
|
||||
/// 黄金储备最低比例(百分比,默认40)
|
||||
pub min_gold_reserve_ratio: u8,
|
||||
/// 当前黄金储备比例
|
||||
pub current_gold_reserve_ratio: u8,
|
||||
pub pending_events: Vec<XTZHProtocolEvent>,
|
||||
pub created_at: Timestamp,
|
||||
pub updated_at: Timestamp,
|
||||
}
|
||||
impl XTZHStablecoinProtocol {
|
||||
pub fn new(sdr_peg_rate: u128, min_gold_reserve_ratio: u8) -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.XTZHStablecoinProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-XTZH".to_string(),
|
||||
total_supply: 0,
|
||||
holdings: HashMap::new(),
|
||||
reserve_assets: Vec::new(),
|
||||
sdr_peg_rate,
|
||||
sdr_tolerance_bps: 200,
|
||||
min_gold_reserve_ratio,
|
||||
current_gold_reserve_ratio: 0,
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
}
|
||||
impl XTZHStablecoinProtocol {
|
||||
pub fn new(sdr_peg_rate: u128, min_gold_reserve_ratio: u8) -> Self {
|
||||
Self {
|
||||
protocol_uid: "nac.acc.XTZHStablecoinProtocol.v1".to_string(),
|
||||
lens_protocol_vector: "ACC-XTZH".to_string(),
|
||||
total_supply: 0,
|
||||
holdings: HashMap::new(),
|
||||
reserve_assets: Vec::new(),
|
||||
sdr_peg_rate,
|
||||
sdr_tolerance_bps: 200,
|
||||
min_gold_reserve_ratio,
|
||||
current_gold_reserve_ratio: 0,
|
||||
pending_events: Vec::new(),
|
||||
created_at: Timestamp::now(),
|
||||
updated_at: Timestamp::now(),
|
||||
}
|
||||
pub fn mint(
|
||||
&mut self, recipient: Address, amount: u128,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCXTZHError::InvalidConstitutionalReceipt); }
|
||||
if self.current_gold_reserve_ratio < self.min_gold_reserve_ratio {
|
||||
return Err(ACCXTZHError::GoldReserveInsufficient {
|
||||
required_ratio: self.min_gold_reserve_ratio,
|
||||
actual_ratio: self.current_gold_reserve_ratio,
|
||||
});
|
||||
}
|
||||
pub fn mint(
|
||||
&mut self, recipient: Address, amount: u128,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCXTZHError::InvalidConstitutionalReceipt); }
|
||||
if self.current_gold_reserve_ratio < self.min_gold_reserve_ratio {
|
||||
return Err(ACCXTZHError::GoldReserveInsufficient {
|
||||
required_ratio: self.min_gold_reserve_ratio,
|
||||
actual_ratio: self.current_gold_reserve_ratio,
|
||||
});
|
||||
}
|
||||
*self.holdings.entry(recipient.clone()).or_insert(0) += amount;
|
||||
self.total_supply = self.total_supply.saturating_add(amount);
|
||||
self.pending_events.push(XTZHProtocolEvent::Minted { recipient, amount, constitutional_receipt, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn burn(
|
||||
&mut self, holder: Address, amount: u128,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCXTZHError::InvalidConstitutionalReceipt); }
|
||||
let balance = self.holdings.get(&holder).copied().unwrap_or(0);
|
||||
if balance < amount {
|
||||
return Err(ACCXTZHError::InsufficientBalance { holder: holder.clone(), available: balance, requested: amount });
|
||||
}
|
||||
*self.holdings.get_mut(&holder).unwrap() -= amount;
|
||||
self.total_supply = self.total_supply.saturating_sub(amount);
|
||||
self.pending_events.push(XTZHProtocolEvent::Burned { holder, amount, constitutional_receipt, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn transfer(
|
||||
&mut self, from: Address, to: Address, amount: u128, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
let balance = self.holdings.get(&from).copied().unwrap_or(0);
|
||||
if balance < amount {
|
||||
return Err(ACCXTZHError::InsufficientBalance { holder: from.clone(), available: balance, requested: amount });
|
||||
}
|
||||
*self.holdings.get_mut(&from).unwrap() -= amount;
|
||||
*self.holdings.entry(to.clone()).or_insert(0) += amount;
|
||||
self.pending_events.push(XTZHProtocolEvent::Transferred { from, to, amount, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn update_sdr_rate(
|
||||
&mut self, new_rate: u128, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCXTZHError::InvalidConstitutionalReceipt); }
|
||||
let tolerance = self.sdr_peg_rate * self.sdr_tolerance_bps as u128 / 10000;
|
||||
let min_rate = self.sdr_peg_rate.saturating_sub(tolerance);
|
||||
let max_rate = self.sdr_peg_rate.saturating_add(tolerance);
|
||||
if new_rate < min_rate || new_rate > max_rate {
|
||||
return Err(ACCXTZHError::SDRPegViolation { current_rate: new_rate, min_rate, max_rate });
|
||||
}
|
||||
let old_rate = self.sdr_peg_rate;
|
||||
self.sdr_peg_rate = new_rate;
|
||||
self.pending_events.push(XTZHProtocolEvent::SDRRateUpdated { old_rate, new_rate, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn update_reserve(
|
||||
&mut self, asset_type: ReserveAssetType, amount: u128, weight_bps: u16, timestamp: Timestamp,
|
||||
) {
|
||||
if let Some(r) = self.reserve_assets.iter_mut().find(|r| r.asset_type == asset_type) {
|
||||
r.amount = amount;
|
||||
r.weight_bps = weight_bps;
|
||||
r.last_updated = timestamp;
|
||||
} else {
|
||||
self.reserve_assets.push(ReserveAsset { asset_type, amount, weight_bps, last_updated: timestamp });
|
||||
}
|
||||
self.recalculate_gold_ratio();
|
||||
}
|
||||
fn recalculate_gold_ratio(&mut self) {
|
||||
let total_weight: u16 = self.reserve_assets.iter().map(|r| r.weight_bps).sum();
|
||||
if total_weight == 0 { self.current_gold_reserve_ratio = 0; return; }
|
||||
let gold_weight: u16 = self.reserve_assets.iter()
|
||||
.filter(|r| r.asset_type == ReserveAssetType::Gold)
|
||||
.map(|r| r.weight_bps).sum();
|
||||
self.current_gold_reserve_ratio = (gold_weight as u32 * 100 / total_weight as u32) as u8;
|
||||
}
|
||||
pub fn balance_of(&self, address: &Address) -> u128 { self.holdings.get(address).copied().unwrap_or(0) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<XTZHProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
*self.holdings.entry(recipient.clone()).or_insert(0) += amount;
|
||||
self.total_supply = self.total_supply.saturating_add(amount);
|
||||
self.pending_events.push(XTZHProtocolEvent::Minted { recipient, amount, constitutional_receipt, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn burn(
|
||||
&mut self, holder: Address, amount: u128,
|
||||
constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCXTZHError::InvalidConstitutionalReceipt); }
|
||||
let balance = self.holdings.get(&holder).copied().unwrap_or(0);
|
||||
if balance < amount {
|
||||
return Err(ACCXTZHError::InsufficientBalance { holder: holder.clone(), available: balance, requested: amount });
|
||||
}
|
||||
*self.holdings.get_mut(&holder).unwrap() -= amount;
|
||||
self.total_supply = self.total_supply.saturating_sub(amount);
|
||||
self.pending_events.push(XTZHProtocolEvent::Burned { holder, amount, constitutional_receipt, timestamp });
|
||||
self.updated_at = Timestamp::now();
|
||||
Ok(())
|
||||
}
|
||||
pub fn transfer(
|
||||
&mut self, from: Address, to: Address, amount: u128, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
let balance = self.holdings.get(&from).copied().unwrap_or(0);
|
||||
if balance < amount {
|
||||
return Err(ACCXTZHError::InsufficientBalance { holder: from.clone(), available: balance, requested: amount });
|
||||
}
|
||||
*self.holdings.get_mut(&from).unwrap() -= amount;
|
||||
*self.holdings.entry(to.clone()).or_insert(0) += amount;
|
||||
self.pending_events.push(XTZHProtocolEvent::Transferred { from, to, amount, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn update_sdr_rate(
|
||||
&mut self, new_rate: u128, constitutional_receipt: Hash, timestamp: Timestamp,
|
||||
) -> Result<(), ACCXTZHError> {
|
||||
if constitutional_receipt.is_zero() { return Err(ACCXTZHError::InvalidConstitutionalReceipt); }
|
||||
let tolerance = self.sdr_peg_rate * self.sdr_tolerance_bps as u128 / 10000;
|
||||
let min_rate = self.sdr_peg_rate.saturating_sub(tolerance);
|
||||
let max_rate = self.sdr_peg_rate.saturating_add(tolerance);
|
||||
if new_rate < min_rate || new_rate > max_rate {
|
||||
return Err(ACCXTZHError::SDRPegViolation { current_rate: new_rate, min_rate, max_rate });
|
||||
}
|
||||
let old_rate = self.sdr_peg_rate;
|
||||
self.sdr_peg_rate = new_rate;
|
||||
self.pending_events.push(XTZHProtocolEvent::SDRRateUpdated { old_rate, new_rate, timestamp });
|
||||
Ok(())
|
||||
}
|
||||
pub fn update_reserve(
|
||||
&mut self, asset_type: ReserveAssetType, amount: u128, weight_bps: u16, timestamp: Timestamp,
|
||||
) {
|
||||
if let Some(r) = self.reserve_assets.iter_mut().find(|r| r.asset_type == asset_type) {
|
||||
r.amount = amount;
|
||||
r.weight_bps = weight_bps;
|
||||
r.last_updated = timestamp;
|
||||
} else {
|
||||
self.reserve_assets.push(ReserveAsset { asset_type, amount, weight_bps, last_updated: timestamp });
|
||||
}
|
||||
self.recalculate_gold_ratio();
|
||||
}
|
||||
fn recalculate_gold_ratio(&mut self) {
|
||||
let total_weight: u16 = self.reserve_assets.iter().map(|r| r.weight_bps).sum();
|
||||
if total_weight == 0 { self.current_gold_reserve_ratio = 0; return; }
|
||||
let gold_weight: u16 = self.reserve_assets.iter()
|
||||
.filter(|r| r.asset_type == ReserveAssetType::Gold)
|
||||
.map(|r| r.weight_bps).sum();
|
||||
self.current_gold_reserve_ratio = (gold_weight as u32 * 100 / total_weight as u32) as u8;
|
||||
}
|
||||
pub fn balance_of(&self, address: &Address) -> u128 { self.holdings.get(address).copied().unwrap_or(0) }
|
||||
pub fn drain_pending_events(&mut self) -> Vec<XTZHProtocolEvent> { std::mem::take(&mut self.pending_events) }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue