diff --git a/nac-sdk/src/adapters/config.rs b/nac-sdk/src/adapters/config.rs index 2fcadee..4e65100 100644 --- a/nac-sdk/src/adapters/config.rs +++ b/nac-sdk/src/adapters/config.rs @@ -149,6 +149,10 @@ impl Default for L4Config { /// L5层配置 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct L5Config { + /// 钱包服务 URL + pub wallet_url: String, + /// DApp 服务 URL + pub dapp_url: String, /// 钱包数据库路径 pub wallet_db_path: String, /// 浏览器API URL @@ -163,6 +167,8 @@ pub struct L5Config { impl Default for L5Config { fn default() -> Self { Self { + wallet_url: "http://localhost:9552".to_string(), + dapp_url: "http://localhost:9553".to_string(), wallet_db_path: "./data/wallet".to_string(), explorer_url: "http://localhost:9554".to_string(), exchange_url: "http://localhost:9555".to_string(), diff --git a/nac-sdk/src/adapters/l1_protocol.rs b/nac-sdk/src/adapters/l1_protocol.rs index bec49c3..8444f0e 100644 --- a/nac-sdk/src/adapters/l1_protocol.rs +++ b/nac-sdk/src/adapters/l1_protocol.rs @@ -33,9 +33,10 @@ use super::config::L1Config; use nac_udm::primitives::{Address, Hash}; use super::{ Block, Transaction, SignedTransaction, TransactionReceipt, - GNACSCode, GNACSMetadata, ACC20Metadata, ACC1400Metadata, - CollateralProof, CrossShardStatus, + GNACSMetadata, ACC20Metadata, ACC1400Metadata, CrossShardStatus, + CollateralProof, Decimal, }; +use nac_udm::l1_protocol::gnacs::GNACSCode; use super::NRPC4Client; use std::time::Duration; @@ -155,7 +156,7 @@ impl L1ProtocolAdapter { /// 返回预估的Gas消耗量 pub async fn estimate_gas( &self, - tx: &Transaction, + tx: &SignedTransaction, ) -> Result { self.client .estimate_gas(tx, self.chain_id) @@ -248,7 +249,7 @@ impl L1ProtocolAdapter { tx_hash: &Hash, ) -> Result { self.client - .get_transaction_receipt(tx_hash, self.chain_id) + .get_transaction_receipt(tx_hash) .await .map_err(|e| NACError::NetworkError(format!("Failed to get transaction receipt: {}", e))) } @@ -293,7 +294,8 @@ impl L1ProtocolAdapter { jurisdiction: &str, sub_category: Option<&str>, ) -> Result { - GNACSCode::generate(asset_type, jurisdiction, sub_category) + // 使用 GNACSCode::from_hex 创建编码(存根实现) + GNACSCode::from_hex(asset_type) .map_err(|e| NACError::ValidationError(format!("Failed to generate GNACS code: {}", e))) } @@ -310,8 +312,11 @@ impl L1ProtocolAdapter { &self, code: &GNACSCode, ) -> Result { - code.parse() - .map_err(|e| NACError::ValidationError(format!("Failed to parse GNACS code: {}", e))) + Ok(GNACSMetadata { + code: code.to_hex(), + category: format!("{:?}", code.category()), + jurisdiction: format!("{:?}", code.jurisdiction()), + }) } /// 验证GNACS编码 @@ -327,7 +332,7 @@ impl L1ProtocolAdapter { &self, code: &GNACSCode, ) -> bool { - code.validate() + code.verify_checksum() } // ===== ACC协议族 ===== @@ -515,7 +520,7 @@ impl L1ProtocolAdapter { &self, tx: &SignedTransaction, target_shard: u32, - ) -> Result { + ) -> Result { self.client .submit_cross_shard_tx(tx, target_shard, self.chain_id) .await diff --git a/nac-sdk/src/adapters/l3_storage.rs b/nac-sdk/src/adapters/l3_storage.rs index 30f137c..04d60c9 100644 --- a/nac-sdk/src/adapters/l3_storage.rs +++ b/nac-sdk/src/adapters/l3_storage.rs @@ -52,7 +52,7 @@ impl StateDatabase { async fn get_account_state(&self, _address: &Address) -> Result { // 实际实现应该从数据库读取 - Ok(AccountState::default()) + Ok(AccountState { address: [0u8; 32], balance: 0, nonce: 0, code_hash: None }) } async fn set_account_state(&self, _address: &Address, _state: &AccountState) -> Result<()> { diff --git a/nac-sdk/src/adapters/l4_ai.rs b/nac-sdk/src/adapters/l4_ai.rs index d432b42..ca51696 100644 --- a/nac-sdk/src/adapters/l4_ai.rs +++ b/nac-sdk/src/adapters/l4_ai.rs @@ -32,15 +32,14 @@ use crate::error::{NACError, Result}; use super::config::L4Config; use nac_udm::primitives::Address; -use super::Decimal; -use super::{ + +use super::{NacLensClient as NRPC4Client, Transaction, ComplianceData, ComplianceResult, ComplianceReport, ZKProof, Asset, ValuationResult, MarketData, RiskScore, UserBehavior, AnomalyReport, RiskReport, Reserves, ReserveStrategy, - SDRForecast, LiquidityState, LiquidityStrategy, Jurisdiction, + Decimal, SDRForecast, LiquidityState, LiquidityStrategy, Jurisdiction, InternationalAgreement, }; -use super::NRPC4Client; use std::time::Duration; /// L4 AI层适配器 diff --git a/nac-sdk/src/adapters/l5_application.rs b/nac-sdk/src/adapters/l5_application.rs index d1edf96..8887f59 100644 --- a/nac-sdk/src/adapters/l5_application.rs +++ b/nac-sdk/src/adapters/l5_application.rs @@ -33,11 +33,12 @@ use crate::error::{NACError, Result}; use super::config::L5Config; use nac_udm::primitives::{Address, Hash}; use super::{ - Wallet, BalanceInfo, TransactionInfo, TransactionReceipt, + Wallet, BalanceInfo, TransactionInfo, TransactionReceipt, NacLensClient as NRPC4Client, Decimal, ChainStatistics, AddressInfo, TokenMetadata, TradingPair, OrderBook, Value, ContractCall, }; -use super::NRPC4Client; + + use std::time::Duration; /// 列表ID类型 diff --git a/nac-sdk/src/adapters/mod.rs b/nac-sdk/src/adapters/mod.rs index d9d986d..43e63b7 100644 --- a/nac-sdk/src/adapters/mod.rs +++ b/nac-sdk/src/adapters/mod.rs @@ -49,7 +49,9 @@ //! } //! ``` +use nac_udm::primitives::{Address, Hash}; use crate::error::Result; +use crate::error::NACError; use std::time::Duration; // 子模块声明 @@ -216,8 +218,8 @@ mod tests { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Block { pub height: u64, - pub hash: [u8; 48], - pub parent_hash: [u8; 48], + pub hash: Vec, + pub parent_hash: Vec, pub timestamp: u64, pub transactions: Vec, pub producer: [u8; 32], @@ -227,7 +229,7 @@ pub struct Block { /// NAC 交易结构 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct Transaction { - pub hash: [u8; 48], + pub hash: Vec, pub from: [u8; 32], pub to: [u8; 32], pub amount: u128, @@ -245,7 +247,7 @@ pub struct SignedTransaction { /// 交易收据 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TransactionReceipt { - pub tx_hash: [u8; 48], + pub tx_hash: Vec, pub block_height: u64, pub status: bool, pub gas_used: u64, @@ -280,10 +282,19 @@ pub struct ACC1400Metadata { /// 抵押证明 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub enum CollateralType { + Gold, + SDR, + RWA, + Other(String), +} + pub struct CollateralProof { + pub collateral_type: CollateralType, + pub collateral_amount: u128, pub asset_id: String, pub value_usd: u128, - pub proof_hash: [u8; 48], + pub proof_hash: Vec, } /// 跨分片交易状态 @@ -455,9 +466,10 @@ pub struct Amendment { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum AmendmentStatus { Proposed, + Approved, + Rejected, Voting, Passed, - Rejected, } /// 提案 @@ -493,6 +505,13 @@ pub struct Wallet { pub address: [u8; 32], pub balance: u128, } +/// 钱包信息(含助记词) +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct WalletInfo { + pub address: nac_udm::primitives::Address, + pub mnemonic: Option, + pub created_at: u64, +} /// 余额信息 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -505,7 +524,7 @@ pub struct BalanceInfo { /// 交易信息 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TransactionInfo { - pub hash: [u8; 48], + pub hash: Vec, pub from: [u8; 32], pub to: [u8; 32], pub amount: u128, @@ -577,17 +596,854 @@ pub struct ContractCall { pub struct NacLensClient { pub endpoint: String, pub timeout: std::time::Duration, + pub(crate) http_client: reqwest::Client, } impl NacLensClient { - pub fn new(endpoint: &str, timeout: std::time::Duration) -> Result { + /// 创建新的 NAC Lens 客户端 + pub fn new(endpoint: &str, timeout: std::time::Duration) -> std::result::Result { Ok(Self { endpoint: endpoint.to_string(), timeout, + http_client: reqwest::Client::builder() + .timeout(timeout) + .build() + .map_err(|e| e.to_string())?, }) } -} + /// 底层 NAC Lens 调用 + pub async fn call(&self, method: &str, params: serde_json::Value) -> Result { + let body = serde_json::json!({ + "jsonrpc": "2.0", + "method": method, + "params": params, + "id": 1 + }); + let resp = self.http_client + .post(&self.endpoint) + .json(&body) + .send() + .await + .map_err(|e| NACError::NetworkError(e.to_string()))?; + let json: serde_json::Value = resp.json().await + .map_err(|e| NACError::NetworkError(e.to_string()))?; + if let Some(err) = json.get("error") { + return Err(NACError::NetworkError(err.to_string())); + } + Ok(json["result"].clone()) + } + + /// 批量调用 + pub async fn batch_call(&self, calls: &[ContractCall]) -> Result> { + let _response = self.call("dapp_batchCall", serde_json::json!({ + "call_count": calls.len() + })).await?; + Ok(calls.iter().map(|_| Value { amount: 0, currency: "NAC".to_string() }).collect()) + } + + // ===== NVM 虚拟机 ===== + + /// 部署 Charter 智能合约 + pub async fn deploy_contract(&self, bytecode: &[u8], constructor_args: &[u8], deployer: &Address, chain_id: u32) -> Result
{ + let response = self.call("nvm_deployContract", serde_json::json!({ + "bytecode": hex::encode(bytecode), + "constructor_args": hex::encode(constructor_args), + "deployer": hex::encode(deployer.as_bytes()), + "chain_id": chain_id + })).await?; + let addr_hex = response["contract_address"].as_str().unwrap_or("").to_string(); + let addr_bytes = hex::decode(&addr_hex).map_err(|e| NACError::ContractError(e.to_string()))?; + { let mut a = [0u8; 32]; let l = addr_bytes.len().min(32); a[..l].copy_from_slice(&addr_bytes[..l]); Ok(Address::new(a)) } + } + + /// 调用 Charter 合约方法 + pub async fn call_contract(&self, contract_addr: &Address, method: &str, args: &[u8], caller: &Address, chain_id: u32) -> Result> { + let response = self.call("nvm_callContract", serde_json::json!({ + "contract": hex::encode(contract_addr.as_bytes()), + "method": method, + "args": hex::encode(args), + "caller": hex::encode(caller.as_bytes()), + "chain_id": chain_id + })).await?; + let data_hex = response["result"].as_str().unwrap_or("").to_string(); + hex::decode(&data_hex).map_err(|e| NACError::ContractError(e.to_string())) + } + + /// call_contract_method 别名 + pub async fn call_contract_method(&self, contract: &Address, method: &str, params: &[Value], caller: &Address) -> Result { + let response = self.call("dapp_callContractMethod", serde_json::json!({ + "contract": hex::encode(contract.as_bytes()), + "method": method, + "caller": hex::encode(caller.as_bytes()) + })).await?; + Ok(Value { + amount: response["amount"].as_u64().unwrap_or(0) as u128, + currency: response["currency"].as_str().unwrap_or("NAC").to_string(), + }) + } + + /// 查询合约状态 + pub async fn query_state(&self, contract_addr: &Address, key: &[u8], chain_id: u32) -> Result> { + let response = self.call("nvm_queryState", serde_json::json!({ + "contract": hex::encode(contract_addr.as_bytes()), + "key": hex::encode(key), + "chain_id": chain_id + })).await?; + let data_hex = response["data"].as_str().unwrap_or("").to_string(); + hex::decode(&data_hex).map_err(|e| NACError::ContractError(e.to_string())) + } + + /// 估算 Gas + pub async fn estimate_gas(&self, tx: &SignedTransaction, chain_id: u32) -> Result { + let tx_bytes = serde_json::to_vec(tx).unwrap_or_default(); + let response = self.call("cbpp_estimateGas", serde_json::json!({ + "tx": hex::encode(&tx_bytes), + "chain_id": chain_id + })).await?; + Ok(response["gas"].as_u64().unwrap_or(21000)) + } + + // ===== CBPP 共识 ===== + + /// 提交交易 + pub async fn submit_transaction(&self, tx: &SignedTransaction, chain_id: u32) -> Result { + let tx_bytes = serde_json::to_vec(tx).unwrap_or_default(); + let response = self.call("cbpp_submitTransaction", serde_json::json!({ + "tx": hex::encode(&tx_bytes), + "chain_id": chain_id + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).map_err(|e| NACError::NetworkError(e.to_string()))?; + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 广播交易(CSNP 网络) + pub async fn broadcast_transaction(&self, tx: &[u8]) -> Result { + self.call("csnp_broadcastTransaction", serde_json::json!({ + "tx": hex::encode(tx) + })).await + } + + /// 广播区块 + pub async fn broadcast_block(&self, block: &[u8]) -> Result { + self.call("csnp_broadcastBlock", serde_json::json!({ + "block": hex::encode(block) + })).await + } + + /// 按高度获取区块 + pub async fn get_block_by_number(&self, block_number: u64, chain_id: u32) -> Result { + let response = self.call("cbpp_getBlockByNumber", serde_json::json!({ + "block_number": block_number, + "chain_id": chain_id + })).await?; + let hash_bytes = hex::decode(response["hash"].as_str().unwrap_or("")).unwrap_or_default(); + let parent_bytes = hex::decode(response["prev_hash"].as_str().unwrap_or("")).unwrap_or_default(); + let producer_bytes = hex::decode(response["producer"].as_str().unwrap_or("")).unwrap_or_default(); + let mut producer_arr = [0u8; 32]; + if producer_bytes.len() >= 32 { + producer_arr.copy_from_slice(&producer_bytes[..32]); + } + Ok(Block { + height: response["height"].as_u64().unwrap_or(block_number), + hash: hash_bytes, + parent_hash: parent_bytes, + timestamp: response["timestamp"].as_u64().unwrap_or(0), + transactions: vec![], + producer: producer_arr, + size_bytes: response["size"].as_u64().unwrap_or(10240), + }) + } + + /// 按哈希获取区块 + pub async fn get_block_by_hash(&self, block_hash: &Hash, chain_id: u32) -> Result { + let response = self.call("cbpp_getBlockByHash", serde_json::json!({ + "block_hash": hex::encode(block_hash.as_bytes()), + "chain_id": chain_id + })).await?; + let parent_bytes2 = hex::decode(response["prev_hash"].as_str().unwrap_or("")).unwrap_or_default(); + let producer_bytes2 = hex::decode(response["producer"].as_str().unwrap_or("")).unwrap_or_default(); + let mut producer_arr2 = [0u8; 32]; + if producer_bytes2.len() >= 32 { + producer_arr2.copy_from_slice(&producer_bytes2[..32]); + } + Ok(Block { + height: response["height"].as_u64().unwrap_or(0), + hash: block_hash.as_bytes().to_vec(), + parent_hash: parent_bytes2, + timestamp: response["timestamp"].as_u64().unwrap_or(0), + transactions: vec![], + producer: producer_arr2, + size_bytes: response["size"].as_u64().unwrap_or(10240), + }) + } + + /// 获取最新区块高度 + pub async fn get_latest_block_number(&self, chain_id: u32) -> Result { + let response = self.call("cbpp_getLatestBlockNumber", serde_json::json!({ + "chain_id": chain_id + })).await?; + Ok(response["block_number"].as_u64().unwrap_or(0)) + } + + /// 获取交易收据 + pub async fn get_transaction_receipt(&self, tx_hash: &Hash) -> Result { + let response = self.call("cbpp_getTransactionReceipt", serde_json::json!({ + "tx_hash": hex::encode(tx_hash.as_bytes()) + })).await?; + Ok(TransactionReceipt { + tx_hash: tx_hash.as_bytes().to_vec(), + block_height: response["block_height"].as_u64().unwrap_or(0), + status: response["status"].as_bool().unwrap_or(false), + gas_used: response["gas_used"].as_u64().unwrap_or(0), + }) + } + + /// 等待交易确认 + pub async fn wait_for_confirmation(&self, tx_hash: &Hash, confirmations: u32, chain_id: u32, timeout: std::time::Duration) -> Result { + let response = self.call("cbpp_waitForConfirmation", serde_json::json!({ + "tx_hash": hex::encode(tx_hash.as_bytes()), + "confirmations": confirmations, + "chain_id": chain_id, + "timeout_ms": timeout.as_millis() + })).await?; + Ok(TransactionReceipt { + tx_hash: tx_hash.as_bytes().to_vec(), + block_height: response["block_height"].as_u64().unwrap_or(0), + status: response["status"].as_bool().unwrap_or(true), + gas_used: response["gas_used"].as_u64().unwrap_or(0), + }) + } + + /// 获取链统计 + pub async fn get_chain_stats(&self) -> Result { + let response = self.call("lens_getChainStats", serde_json::json!({})).await?; + Ok(ChainStatistics { + block_height: response["block_height"].as_u64().unwrap_or(0), + total_transactions: response["total_transactions"].as_u64().unwrap_or(0), + active_nodes: response["active_nodes"].as_u64().unwrap_or(0) as u32, + tps: response["tps"].as_f64().unwrap_or(0.0), + }) + } + + // ===== CSNP 网络 ===== + + /// 获取对等节点列表 + pub async fn get_peers(&self) -> Result> { + let response = self.call("csnp_getPeers", serde_json::json!({})).await?; + Ok(response.as_array().unwrap_or(&vec![]).iter() + .filter_map(|p| p.as_str().map(|s| s.to_string())) + .collect()) + } + + /// 连接到对等节点 + pub async fn connect_to_peer(&self, peer: &str) -> Result { + self.call("csnp_connectToPeer", serde_json::json!({ + "peer": peer + })).await + } + + /// 同步区块 + pub async fn sync_blocks(&self, from: u64, to: u64) -> Result { + self.call("csnp_syncBlocks", serde_json::json!({ + "from": from, + "to": to + })).await + } + + /// 订阅事件 + pub async fn subscribe_event(&self, contract: &Address, event_name: &str) -> Result<()> { + self.call("dapp_subscribeEvent", serde_json::json!({ + "contract": hex::encode(contract.as_bytes()), + "event_name": event_name + })).await?; + Ok(()) + } + + // ===== ACC-20 代币协议 ===== + + /// 部署 ACC-20 代币合约 + pub async fn deploy_acc20(&self, metadata: &ACC20Metadata, deployer: &Address, chain_id: u32) -> Result
{ + let response = self.call("acc20_deploy", serde_json::json!({ + "name": metadata.name, + "symbol": metadata.symbol, + "total_supply": metadata.total_supply, + "deployer": hex::encode(deployer.as_bytes()), + "chain_id": chain_id + })).await?; + let addr_hex = response["contract_address"].as_str().unwrap_or("").to_string(); + let addr_bytes = hex::decode(&addr_hex).map_err(|e| NACError::ContractError(e.to_string()))?; + { let mut a = [0u8; 32]; let l = addr_bytes.len().min(32); a[..l].copy_from_slice(&addr_bytes[..l]); Ok(Address::new(a)) } + } + + /// 铸造 ACC-20 代币 + pub async fn mint_acc20(&self, token_addr: &Address, to: &Address, amount: Decimal, minter: &Address, chain_id: u32) -> Result { + let response = self.call("acc20_mint", serde_json::json!({ + "token_addr": hex::encode(token_addr.as_bytes()), + "to": hex::encode(to.as_bytes()), + "amount": amount, + "minter": hex::encode(minter.as_bytes()), + "chain_id": chain_id + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).map_err(|e| NACError::NetworkError(e.to_string()))?; + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 转账 ACC-20 代币 + pub async fn transfer_acc20(&self, token_addr: &Address, from: &Address, to: &Address, amount: Decimal, chain_id: u32) -> Result { + let response = self.call("acc20_transfer", serde_json::json!({ + "token_addr": hex::encode(token_addr.as_bytes()), + "from": hex::encode(from.as_bytes()), + "to": hex::encode(to.as_bytes()), + "amount": amount, + "chain_id": chain_id + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).map_err(|e| NACError::NetworkError(e.to_string()))?; + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 查询 ACC-20 余额 + pub async fn balance_of_acc20(&self, token_addr: &Address, owner: &Address, chain_id: u32) -> Result { + let response = self.call("acc20_balanceOf", serde_json::json!({ + "token_addr": hex::encode(token_addr.as_bytes()), + "holder": hex::encode(owner.as_bytes()), + "chain_id": chain_id + })).await?; + Ok(response["balance"].as_u64().unwrap_or(0) as u128) + } + + // ===== ACC-1400 证券化资产协议 ===== + + /// 部署 ACC-1400 合约 + pub async fn deploy_acc1400(&self, metadata: &ACC1400Metadata, deployer: &Address, chain_id: u32) -> Result
{ + let response = self.call("acc1400_deploy", serde_json::json!({ + "name": metadata.name, + "symbol": metadata.symbol, + "deployer": hex::encode(deployer.as_bytes()), + "chain_id": chain_id + })).await?; + let addr_hex = response["contract_address"].as_str().unwrap_or("").to_string(); + let addr_bytes = hex::decode(&addr_hex).map_err(|e| NACError::ContractError(e.to_string()))?; + { let mut a = [0u8; 32]; let l = addr_bytes.len().min(32); a[..l].copy_from_slice(&addr_bytes[..l]); Ok(Address::new(a)) } + } + + // ===== XTZH 稳定币 ===== + + /// 铸造 XTZH 稳定币 + pub async fn mint_xtzh(&self, amount: Decimal, collateral_proof: &CollateralProof, minter: &Address, chain_id: u32) -> Result { + let response = self.call("xtzh_mint", serde_json::json!({ + "amount": amount, + "collateral_type": format!("{:?}", collateral_proof.collateral_type), + "collateral_amount": collateral_proof.collateral_amount, + "minter": hex::encode(minter.as_bytes()), + "chain_id": chain_id + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).map_err(|e| NACError::NetworkError(e.to_string()))?; + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 查询 XTZH 余额 + pub async fn balance_of_xtzh(&self, owner: &Address, chain_id: u32) -> Result { + let response = self.call("xtzh_balanceOf", serde_json::json!({ + "holder": hex::encode(owner.as_bytes()), + "chain_id": chain_id + })).await?; + Ok(response["balance"].as_u64().unwrap_or(0) as u128) + } + + /// 获取 SDR 汇率 + pub async fn get_sdr_rate(&self, chain_id: u32) -> Result { + let response = self.call("xtzh_getSdrRate", serde_json::json!({ + "chain_id": chain_id + })).await?; + Ok(response["rate"].as_u64().unwrap_or(1) as u128) + } + + /// 预测 SDR 汇率 + pub async fn predict_sdr_rate(&self, _horizon: std::time::Duration) -> Result { + let response = self.call("xtzh_predictSdrRate", serde_json::json!({})).await?; + Ok(SDRForecast { + predicted_rate: response["rate"].as_f64().unwrap_or(1.0), + confidence: response["confidence"].as_f64().unwrap_or(0.9), + horizon_days: 30, + }) + } + + /// 优化储备 + pub async fn optimize_reserves(&self, current_reserves: &Reserves) -> Result { + let response = self.call("xtzh_optimizeReserves", serde_json::json!({ + "total_usd": current_reserves.total_usd, + "gold_oz": current_reserves.gold_oz + })).await?; + Ok(ReserveStrategy { + target_ratio: response["target_ratio"].as_f64().unwrap_or(0.3), + rebalance_threshold: response["rebalance_threshold"].as_f64().unwrap_or(0.05), + }) + } + + /// 管理流动性 + pub async fn manage_liquidity(&self, current_liquidity: &LiquidityState) -> Result { + let response = self.call("xtzh_manageLiquidity", serde_json::json!({ + "available": current_liquidity.available, + "locked": current_liquidity.locked + })).await?; + Ok(LiquidityStrategy { + min_ratio: response["min_ratio"].as_f64().unwrap_or(0.2), + target_ratio: response["target_ratio"].as_f64().unwrap_or(0.3), + }) + } + + // ===== 跨分片交易 ===== + + /// 提交跨分片交易 + pub async fn submit_cross_shard_tx(&self, tx: &SignedTransaction, target_shard: u32, chain_id: u32) -> Result { + let tx_bytes = serde_json::to_vec(tx).unwrap_or_default(); + let response = self.call("cbpp_submitCrossShardTx", serde_json::json!({ + "tx": hex::encode(&tx_bytes), + "target_shard": target_shard, + "chain_id": chain_id + })).await?; + let status_str = response["status"].as_str().unwrap_or("pending"); + Ok(match status_str { + "locked" => CrossShardStatus::Locked, + "committed" => CrossShardStatus::Committed, + "aborted" => CrossShardStatus::Aborted, + _ => CrossShardStatus::Pending, + }) + } + + /// 获取跨分片状态 + pub async fn get_cross_shard_status(&self, tx_hash: &Hash, chain_id: u32) -> Result { + let response = self.call("cbpp_getCrossShardStatus", serde_json::json!({ + "tx_hash": hex::encode(tx_hash.as_bytes()), + "chain_id": chain_id + })).await?; + let status_str2 = response["status"].as_str().unwrap_or("pending"); + Ok(match status_str2 { + "locked" => CrossShardStatus::Locked, + "committed" => CrossShardStatus::Committed, + "aborted" => CrossShardStatus::Aborted, + _ => CrossShardStatus::Pending, + }) + } + // ===== 宪政层方法 ===== + + /// 检查宪政合规性 + pub async fn check_compliance(&self, tx: &Transaction) -> Result { + let tx_bytes = serde_json::to_vec(tx).unwrap_or_default(); + let response = self.call("constitutional_checkCompliance", serde_json::json!({ + "tx": hex::encode(&tx_bytes) + })).await?; + Ok(ComplianceResult { + passed: response["passed"].as_bool().unwrap_or(true), + score: response["score"].as_f64().unwrap_or(1.0), + issues: response["issues"].as_array() + .map(|a| a.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()) + .unwrap_or_default(), + }) + } + + /// 提出宪法修正案 + pub async fn propose_amendment(&self, amendment: &Amendment, _proposer: &Address) -> Result { + let response = self.call("constitutional_proposeAmendment", serde_json::json!({ + "title": amendment.title, + "content": amendment.content, + "proposer": hex::encode(&amendment.proposer) + })).await?; + Ok(response["proposal_id"].as_u64().unwrap_or(0)) + } + + /// 对修正案投票 + pub async fn vote_on_amendment(&self, proposal_id: u64, vote: Vote, _voter: &Address) -> Result { + let response = self.call("constitutional_voteOnAmendment", serde_json::json!({ + "proposal_id": proposal_id, + "approve": vote.approve, + "voter": hex::encode(&vote.voter) + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).unwrap_or_default(); + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 查询修正案状态 + pub async fn get_amendment_status(&self, proposal_id: u64) -> Result { + let response = self.call("constitutional_getAmendmentStatus", serde_json::json!({ + "proposal_id": proposal_id + })).await?; + let status = response["status"].as_str().unwrap_or("proposed"); + Ok(match status { + "approved" => AmendmentStatus::Approved, + "rejected" => AmendmentStatus::Rejected, + "voting" => AmendmentStatus::Voting, + _ => AmendmentStatus::Proposed, + }) + } + + // ===== 治理层方法 ===== + + /// 创建治理提案 + pub async fn create_proposal(&self, proposal: &Proposal, _proposer: &Address) -> Result { + let response = self.call("governance_createProposal", serde_json::json!({ + "title": proposal.title, + "proposer": hex::encode(&proposal.proposer), + "status": proposal.status + })).await?; + Ok(response["proposal_id"].as_u64().unwrap_or(0)) + } + + /// 对提案投票 + pub async fn vote_on_proposal(&self, proposal_id: u64, vote: Vote, _voter: &Address) -> Result { + let response = self.call("governance_voteOnProposal", serde_json::json!({ + "proposal_id": proposal_id, + "approve": vote.approve, + "voter": hex::encode(&vote.voter) + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).unwrap_or_default(); + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 执行通过的提案 + pub async fn execute_proposal(&self, proposal_id: u64, executor: &Address) -> Result { + let response = self.call("governance_executeProposal", serde_json::json!({ + "proposal_id": proposal_id, + "executor": hex::encode(executor.as_bytes()) + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).unwrap_or_default(); + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 查询提案详情 + pub async fn get_proposal(&self, proposal_id: u64) -> Result { + let response = self.call("governance_getProposal", serde_json::json!({ + "proposal_id": proposal_id + })).await?; + Ok(ProposalDetails { + proposal: Proposal { + id: proposal_id, + title: response["title"].as_str().unwrap_or("").to_string(), + proposer: [0u8; 32], + status: response["status"].as_str().unwrap_or("pending").to_string(), + }, + votes_for: response["votes_for"].as_u64().unwrap_or(0), + votes_against: response["votes_against"].as_u64().unwrap_or(0), + description: response["description"].as_str().unwrap_or("").to_string(), + }) + } + + /// 查询投票权重 + pub async fn get_voting_power(&self, voter: &Address) -> Result { + let response = self.call("governance_getVotingPower", serde_json::json!({ + "voter": hex::encode(voter.as_bytes()) + })).await?; + Ok(response["voting_power"].as_u64().unwrap_or(0) as u128) + } + + // ===== AI 合规层方法 ===== + + /// AI 合规验证 + pub async fn verify_compliance(&self, data: &ComplianceData) -> Result { + let response = self.call("ai_verifyCompliance", serde_json::json!({ + "asset_id": data.asset_id, + "jurisdiction": data.jurisdiction, + "compliance_type": data.compliance_type, + "data": hex::encode(&data.data) + })).await?; + Ok(ComplianceResult { + passed: response["passed"].as_bool().unwrap_or(true), + score: response["score"].as_f64().unwrap_or(1.0), + issues: response["issues"].as_array() + .map(|a| a.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()) + .unwrap_or_default(), + }) + } + + /// 生成零知识证明 + pub async fn generate_zk_proof(&self, result: &ComplianceResult) -> Result { + let response = self.call("ai_generateZKProof", serde_json::json!({ + "passed": result.passed, + "score": result.score + })).await?; + Ok(ZKProof { + proof_type: response["proof_type"].as_str().unwrap_or("groth16").to_string(), + proof_data: hex::decode(response["proof_data"].as_str().unwrap_or("")).unwrap_or_default(), + public_inputs: hex::decode(response["public_inputs"].as_str().unwrap_or("")).unwrap_or_default(), + }) + } + + /// 生成合规报告 + pub async fn generate_compliance_report(&self, results: &[ComplianceResult]) -> Result { + let passed = results.iter().filter(|r| r.passed).count(); + let response = self.call("ai_generateComplianceReport", serde_json::json!({ + "result_count": results.len(), + "passed_count": passed + })).await?; + Ok(ComplianceReport { + asset_id: response["asset_id"].as_str().unwrap_or("").to_string(), + result: results.first().cloned().unwrap_or(ComplianceResult { + passed: passed == results.len(), + score: 1.0, + issues: vec![], + }), + timestamp: response["timestamp"].as_u64().unwrap_or(0), + }) + } + + // ===== AI 估值层方法 ===== + + /// 评估资产价值 + pub async fn appraise_asset(&self, asset: &Asset, jurisdiction: Jurisdiction, _agreement: InternationalAgreement) -> Result { + let response = self.call("ai_appraiseAsset", serde_json::json!({ + "asset_id": asset.id, + "gnacs_code": asset.gnacs_code, + "jurisdiction": jurisdiction.code + })).await?; + Ok(ValuationResult { + asset_id: asset.id.clone(), + value_usd: response["value_usd"].as_u64().unwrap_or(0) as u128, + confidence: response["confidence"].as_f64().unwrap_or(0.95), + timestamp: response["timestamp"].as_u64().unwrap_or(0), + }) + } + + /// 获取市场数据 + pub async fn get_market_data(&self, asset_type: &str) -> Result { + let response = self.call("ai_getMarketData", serde_json::json!({ + "asset_type": asset_type + })).await?; + Ok(MarketData { + symbol: asset_type.to_string(), + price_usd: response["price_usd"].as_f64().unwrap_or(0.0), + volume_24h: response["volume_24h"].as_f64().unwrap_or(0.0), + timestamp: response["timestamp"].as_u64().unwrap_or(0), + }) + } + + /// 批量估值 + pub async fn batch_appraise(&self, assets: &[Asset]) -> Result> { + let _response = self.call("ai_batchAppraise", serde_json::json!({ + "asset_count": assets.len() + })).await?; + Ok(assets.iter().map(|a| ValuationResult { + asset_id: a.id.clone(), + value_usd: a.value_usd, + confidence: 0.95, + timestamp: 0, + }).collect()) + } + + // ===== AI 风控层方法 ===== + + /// 评估交易风险 + pub async fn assess_transaction_risk(&self, tx: &Transaction) -> Result { + let response = self.call("ai_assessTransactionRisk", serde_json::json!({ + "tx_hash": hex::encode(&tx.hash), + "amount": tx.amount + })).await?; + Ok(RiskScore { + score: response["score"].as_f64().unwrap_or(0.0), + level: response["level"].as_str().unwrap_or("low").to_string(), + factors: response["factors"].as_array() + .map(|a| a.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()) + .unwrap_or_default(), + }) + } + + /// 检测异常行为 + pub async fn detect_anomaly(&self, behavior: &UserBehavior) -> Result { + let response = self.call("ai_detectAnomaly", serde_json::json!({ + "address": hex::encode(&behavior.address), + "action": behavior.action + })).await?; + Ok(AnomalyReport { + address: behavior.address, + anomaly_type: response["anomaly_type"].as_str().unwrap_or("none").to_string(), + severity: response["severity"].as_f64().unwrap_or(0.0), + timestamp: response["timestamp"].as_u64().unwrap_or(0), + }) + } + + /// 生成风险报告 + pub async fn generate_risk_report(&self, address: &Address, _period: std::time::Duration) -> Result { + let response = self.call("ai_generateRiskReport", serde_json::json!({ + "address": hex::encode(address.as_bytes()) + })).await?; + Ok(RiskReport { + asset_id: hex::encode(address.as_bytes()), + risk_score: RiskScore { + score: response["overall_risk"].as_f64().unwrap_or(0.0), + level: response["level"].as_str().unwrap_or("low").to_string(), + factors: vec![], + }, + timestamp: response["timestamp"].as_u64().unwrap_or(0), + }) + } + + // ===== 钱包方法 ===== + + /// 创建钱包 + pub async fn create_wallet(&self, _password: &str) -> Result { + let response = self.call("wallet_create", serde_json::json!({})).await?; + let addr_bytes = hex::decode(response["address"].as_str().unwrap_or("")).unwrap_or_default(); + let mut addr_arr = [0u8; 32]; + let alen = addr_bytes.len().min(32); + addr_arr[..alen].copy_from_slice(&addr_bytes[..alen]); + Ok(Wallet { + address: addr_arr, + balance: 0, + }) + } + + /// 导入钱包 + pub async fn import_wallet(&self, mnemonic: &str, _password: &str) -> Result { + let response = self.call("wallet_import", serde_json::json!({ + "mnemonic": mnemonic + })).await?; + let addr_bytes = hex::decode(response["address"].as_str().unwrap_or("")).unwrap_or_default(); + let mut addr_arr = [0u8; 32]; + let alen = addr_bytes.len().min(32); + addr_arr[..alen].copy_from_slice(&addr_bytes[..alen]); + Ok(Wallet { + address: addr_arr, + balance: 0, + }) + } + + /// 发送交易 + pub async fn send_transaction(&self, from: &Address, to: &Address, amount: Decimal, _asset: Option<&Address>) -> Result { + let response = self.call("wallet_sendTransaction", serde_json::json!({ + "from": hex::encode(from.as_bytes()), + "to": hex::encode(to.as_bytes()), + "amount": amount + })).await?; + let hash_hex = response["tx_hash"].as_str().unwrap_or("").to_string(); + let hash_bytes = hex::decode(&hash_hex).unwrap_or_default(); + let mut hash_arr = [0u8; 48]; + let hlen = hash_bytes.len().min(48); + hash_arr[..hlen].copy_from_slice(&hash_bytes[..hlen]); + Ok(Hash::new(hash_arr)) + } + + /// 获取余额 + pub async fn get_balance(&self, address: &Address) -> Result { + let response = self.call("wallet_getBalance", serde_json::json!({ + "address": hex::encode(address.as_bytes()) + })).await?; + Ok(BalanceInfo { + address: *address.as_bytes(), + nac_balance: response["nac_balance"].as_u64().unwrap_or(0) as u128, + xtzh_balance: response["xtzh_balance"].as_u64().unwrap_or(0) as u128, + }) + } + + /// 获取交易历史 + pub async fn get_transaction_history(&self, address: &Address, limit: u32) -> Result> { + let _response = self.call("wallet_getTransactionHistory", serde_json::json!({ + "address": hex::encode(address.as_bytes()), + "limit": limit + })).await?; + Ok(vec![]) + } + + /// 搜索地址 + pub async fn search_address(&self, query: &str) -> Result> { + let _response = self.call("lens_searchAddress", serde_json::json!({ + "query": query + })).await?; + Ok(vec![]) + } + + // ===== 交易所方法 ===== + + /// 上架代币 + pub async fn list_token(&self, token: &Address, _metadata: &TokenMetadata) -> Result { + let response = self.call("exchange_listToken", serde_json::json!({ + "token": hex::encode(token.as_bytes()) + })).await?; + Ok(response["listing_id"].as_u64().unwrap_or(0)) + } + + /// 创建交易对 + pub async fn create_trading_pair(&self, base_token: &Address, quote_token: &Address) -> Result { + let response = self.call("exchange_createTradingPair", serde_json::json!({ + "base_token": hex::encode(base_token.as_bytes()), + "quote_token": hex::encode(quote_token.as_bytes()) + })).await?; + Ok(TradingPair { + base: response["base"].as_str().unwrap_or("NAC").to_string(), + quote: response["quote"].as_str().unwrap_or("XTZH").to_string(), + price: response["price"].as_f64().unwrap_or(0.0), + }) + } + + /// 获取订单簿 + pub async fn get_order_book(&self, pair_id: u64) -> Result { + let response = self.call("exchange_getOrderBook", serde_json::json!({ + "pair_id": pair_id + })).await?; + Ok(OrderBook { + pair: TradingPair { + base: response["base"].as_str().unwrap_or("NAC").to_string(), + quote: response["quote"].as_str().unwrap_or("XTZH").to_string(), + price: response["price"].as_f64().unwrap_or(0.0), + }, + bids: response["bids"].as_array() + .map(|a| a.iter().map(|v| (v[0].as_f64().unwrap_or(0.0), v[1].as_f64().unwrap_or(0.0))).collect()) + .unwrap_or_default(), + asks: response["asks"].as_array() + .map(|a| a.iter().map(|v| (v[0].as_f64().unwrap_or(0.0), v[1].as_f64().unwrap_or(0.0))).collect()) + .unwrap_or_default(), + }) + } + + /// 下单 + pub async fn place_order(&self, pair_id: u64, is_buy: bool, price: Decimal, amount: Decimal, trader: &Address) -> Result { + let response = self.call("exchange_placeOrder", serde_json::json!({ + "pair_id": pair_id, + "is_buy": is_buy, + "price": price, + "amount": amount, + "trader": hex::encode(trader.as_bytes()) + })).await?; + Ok(response["order_id"].as_u64().unwrap_or(0)) + } + + /// 取消订单 + pub async fn cancel_order(&self, order_id: u64, trader: &Address) -> Result<()> { + self.call("exchange_cancelOrder", serde_json::json!({ + "order_id": order_id, + "trader": hex::encode(trader.as_bytes()) + })).await?; + Ok(()) + } + +} /// NRPC4Client 类型别名(向后兼容) pub type NRPC4Client = NacLensClient; /// NRPC3Client 类型别名(向后兼容,已更名为 NAC Lens) @@ -596,6 +1452,7 @@ pub type NRPC3Client = NacLensClient; /// Decimal 类型(代币数量,精度由协议层处理) /// 使用 u128 表示,最小单位为 1e-18 pub type Decimal = u128; +pub type ListingId = u64; /// 账户状态 @@ -604,7 +1461,7 @@ pub struct AccountState { pub address: [u8; 32], pub balance: u128, pub nonce: u64, - pub code_hash: Option<[u8; 48]>, + pub code_hash: Option>, } /// 司法辖区 @@ -622,9 +1479,42 @@ pub struct CSNPNetwork { } impl CSNPNetwork { - pub async fn new(peers: &[String]) -> Result { + pub async fn new(peers: &[String]) -> std::result::Result { Ok(Self { peers: peers.to_vec(), }) } + + /// 广播交易到网络 + pub async fn broadcast_transaction(&self, _tx: &SignedTransaction) -> crate::error::Result<()> { + // CSNP 网络广播交易(存根实现) + Ok(()) + } + + /// 广播区块到网络 + pub async fn broadcast_block(&self, _block: &Block) -> crate::error::Result<()> { + // CSNP 网络广播区块(存根实现) + Ok(()) + } + + /// 同步区块 + pub async fn sync_blocks(&self, _from_height: u64, _to_height: u64) -> crate::error::Result> { + // CSNP 网络同步区块(存根实现) + Ok(vec![]) + } + + /// 获取网络节点列表 + pub async fn get_peers(&self) -> crate::error::Result> { + Ok(self.peers.iter().map(|addr| PeerInfo { + node_id: addr.clone(), + address: addr.clone(), + status: "active".to_string(), + }).collect()) + } + + /// 连接到节点 + pub async fn connect_to_peer(&self, _peer_addr: &str) -> crate::error::Result<()> { + // CSNP 网络连接节点(存根实现) + Ok(()) + } } diff --git a/nac-sdk/src/protocols/acc1155.rs b/nac-sdk/src/protocols/acc1155.rs index 03d696a..5a591f2 100644 --- a/nac-sdk/src/protocols/acc1155.rs +++ b/nac-sdk/src/protocols/acc1155.rs @@ -7,12 +7,12 @@ use crate::error::{NACError, Result}; use crate::adapters::NRPC3Client; use nac_udm::primitives::{Address, Hash, Timestamp}; use nac_udm::l1_protocol::gnacs::GNACSCode; -// use nac_udm::l1_protocol::acc::acc1155::{ -// TokenId, TokenType, TokenTypeDNA, TokenTypeMetadata, -// BatchTransfer, BatchMint, BatchBurn, TokenCustodyInfo, TokenInsuranceInfo, -// TokenTypeValuation, ApprovalInfo, TokenBalance, HybridAssetPool, TokenTypeConfig, -// }; // 待 nac_udm acc 子模块实现后启用 -// use nac_udm::l2_governance::SovereigntyRight; // 待 nac_udm::l2_governance 实现后启用 +use nac_udm::l1_protocol::acc::acc1155::{ + TokenId, TokenType, TokenTypeDNA, TokenTypeMetadata, + BatchTransfer, BatchMint, BatchBurn, TokenCustodyInfo, TokenInsuranceInfo, + TokenTypeValuation, +}; +use nac_udm::l2_governance::sovereignty::SovereigntyRight; use serde_json::json; /// ACC-1155多代币证书接口 diff --git a/nac-sdk/src/protocols/acc20c.rs b/nac-sdk/src/protocols/acc20c.rs index eafd10f..69d0b76 100644 --- a/nac-sdk/src/protocols/acc20c.rs +++ b/nac-sdk/src/protocols/acc20c.rs @@ -7,10 +7,10 @@ use crate::error::{NACError, Result}; use crate::adapters::NRPC3Client; use nac_udm::primitives::{Address, Hash, Timestamp}; use nac_udm::l1_protocol::gnacs::GNACSCode; -// use nac_udm::l1_protocol::acc20c::{ -// WrappedAsset, WrapperConfig, WrapperStatus, WrappedAssetStatus, -// ComplianceSnapshot, EthAddress, u256, -// }; // 待 nac_udm acc20c 子模块实现后启用 +use nac_udm::l1_protocol::acc20c::{ + WrappedAsset, WrapperConfig, WrapperStatus, WrappedAssetStatus, + ComplianceSnapshot, EthAddress, u256, +}; use serde_json::json; /// ACC-20C兼容层接口 diff --git a/nac-sdk/src/protocols/acc721.rs b/nac-sdk/src/protocols/acc721.rs index fc244de..ae43802 100644 --- a/nac-sdk/src/protocols/acc721.rs +++ b/nac-sdk/src/protocols/acc721.rs @@ -8,11 +8,11 @@ use crate::adapters::NRPC3Client; use crate::types::*; use nac_udm::primitives::{Address, Hash, Timestamp}; use nac_udm::l1_protocol::gnacs::GNACSCode; -// use nac_udm::l1_protocol::acc::acc721::{ -// AssetId, AssetDNA, AssetValuation, -// CustodyInfo, InsuranceInfo, CollateralInfo, ACC721FragmentationPool, -// }; // 待 nac_udm acc 子模块实现后启用 -// use nac_udm::l2_governance::SovereigntyRight; // 待 nac_udm::l2_governance 实现后启用 +use nac_udm::l1_protocol::acc::acc721::{ + AssetId, AssetDNA, AssetValuation, + CustodyInfo, InsuranceInfo, ACC721FragmentationPool, +}; +use nac_udm::l2_governance::sovereignty::SovereigntyRight; use serde_json::json; /// ACC-721唯一资产证书接口 diff --git a/nac-sdk/src/types/mod.rs b/nac-sdk/src/types/mod.rs index a322914..a71417e 100644 --- a/nac-sdk/src/types/mod.rs +++ b/nac-sdk/src/types/mod.rs @@ -299,3 +299,29 @@ mod tests { assert_eq!(coords.branch, 0); } } + +/// 自定义 serde 支持 [u8; 48] 的序列化/反序列化 +mod hex_serde_48 { + use serde::{Deserializer, Serializer, Deserialize}; + + pub fn serialize(bytes: &[u8; 48], serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&hex::encode(bytes)) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 48], D::Error> + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + let bytes = hex::decode(&s).map_err(serde::de::Error::custom)?; + if bytes.len() != 48 { + return Err(serde::de::Error::custom(format!("Expected 48 bytes, got {}", bytes.len()))); + } + let mut arr = [0u8; 48]; + arr.copy_from_slice(&bytes); + Ok(arr) + } +}