//! ACC-721: 唯一资产证书协议接口 //! //! 提供与NAC区块链上ACC-721证书交互的客户端接口 use crate::client::NRPC3Client; use crate::error::{NACError, Result}; 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, SovereigntyType, AssetDNA, AssetValuation, CustodyInfo, InsuranceInfo, CollateralInfo, FragmentationPool, }; use serde_json::json; /// ACC-721唯一资产证书接口 pub struct ACC721 { client: NRPC3Client, } impl ACC721 { /// 创建新的ACC-721接口实例 pub fn new(client: NRPC3Client) -> Self { Self { client } } /// 获取资产持有者 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 资产持有者地址 pub async fn get_asset_holder( &self, certificate_address: &Address, asset_id: AssetId, ) -> Result
{ let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, }); let response = self.client.call("acc721_getAssetHolder", params).await?; let holder_hex = response["result"] .as_str() .ok_or(NACError::InvalidResponse("Missing holder address".to_string()))?; Address::from_hex(holder_hex) .map_err(|e| NACError::InvalidAddress(format!("Invalid holder address: {}", e))) } /// 铸造唯一资产 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `to` - 接收者地址 /// * `asset_id` - 资产ID /// * `metadata_uri` - 资产元数据URI /// * `physical_fingerprint` - 物理指纹哈希 /// * `legal_document_hash` - 法律文件哈希 /// * `custodian` - 托管方地址 /// * `insurer` - 保险方地址 /// * `insurance_coverage` - 保险金额(XTZH) /// * `insurance_expiry` - 保险到期时间 /// /// # 返回 /// 资产DNA pub async fn mint_asset( &self, certificate_address: &Address, to: &Address, asset_id: AssetId, metadata_uri: String, physical_fingerprint: Hash, legal_document_hash: Hash, custodian: Address, insurer: Address, insurance_coverage: u128, insurance_expiry: Timestamp, ) -> Result { let params = json!({ "certificate_address": certificate_address, "to": to, "asset_id": asset_id, "metadata_uri": metadata_uri, "physical_fingerprint": physical_fingerprint, "legal_document_hash": legal_document_hash, "custodian": custodian, "insurer": insurer, "insurance_coverage": insurance_coverage, "insurance_expiry": insurance_expiry, }); let response = self.client.call("acc721_mintAsset", params).await?; // 解析AssetDNA let dna_data = &response["result"]; let asset_dna = AssetDNA { dna_hash: Hash::from_hex( dna_data["dna_hash"] .as_str() .ok_or(NACError::InvalidResponse("Missing dna_hash".to_string()))? )?, physical_fingerprint, legal_document_hash, generated_at: Timestamp::from_secs( dna_data["generated_at"] .as_u64() .ok_or(NACError::InvalidResponse("Missing generated_at".to_string()))? ), }; Ok(asset_dna) } /// 转移唯一资产 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `from` - 发送者地址 /// * `to` - 接收者地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 宪法收据哈希 pub async fn transfer_asset( &self, certificate_address: &Address, from: &Address, to: &Address, asset_id: AssetId, ) -> Result { let params = json!({ "certificate_address": certificate_address, "from": from, "to": to, "asset_id": asset_id, }); let response = self.client.call("acc721_transferAsset", params).await?; let receipt_hash = response["result"]["constitutional_receipt"] .as_str() .ok_or(NACError::InvalidResponse("Missing constitutional_receipt".to_string()))?; Hash::from_hex(receipt_hash) .map_err(|e| NACError::InvalidHash(format!("Invalid receipt hash: {}", e))) } /// 授权资产 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `owner` - 资产持有者地址 /// * `approved` - 被授权者地址 /// * `asset_id` - 资产ID pub async fn approve_asset( &self, certificate_address: &Address, owner: &Address, approved: &Address, asset_id: AssetId, ) -> Result<()> { let params = json!({ "certificate_address": certificate_address, "owner": owner, "approved": approved, "asset_id": asset_id, }); self.client.call("acc721_approveAsset", params).await?; Ok(()) } /// 销毁资产 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `owner` - 资产持有者地址 /// * `asset_id` - 资产ID pub async fn burn_asset( &self, certificate_address: &Address, owner: &Address, asset_id: AssetId, ) -> Result<()> { let params = json!({ "certificate_address": certificate_address, "owner": owner, "asset_id": asset_id, }); self.client.call("acc721_burnAsset", params).await?; Ok(()) } /// 碎片化资产 /// /// 将唯一资产碎片化为多个ACC-20代币 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `owner` - 资产持有者地址 /// * `asset_id` - 资产ID /// * `fragment_count` - 碎片总数 /// * `fragment_price` - 碎片价格(XTZH) /// /// # 返回 /// 碎片化池信息 pub async fn fragmentize_asset( &self, certificate_address: &Address, owner: &Address, asset_id: AssetId, fragment_count: u64, fragment_price: u128, ) -> Result { let params = json!({ "certificate_address": certificate_address, "owner": owner, "asset_id": asset_id, "fragment_count": fragment_count, "fragment_price": fragment_price, }); let response = self.client.call("acc721_fragmentizeAsset", params).await?; // 解析FragmentationPool let pool_data = &response["result"]; let pool = FragmentationPool { fragment_token_address: Address::from_hex( pool_data["fragment_token_address"] .as_str() .ok_or(NACError::InvalidResponse("Missing fragment_token_address".to_string()))? )?, total_fragments: pool_data["total_fragments"] .as_u64() .ok_or(NACError::InvalidResponse("Missing total_fragments".to_string()))?, fragment_price_xtzh: pool_data["fragment_price_xtzh"] .as_str() .ok_or(NACError::InvalidResponse("Missing fragment_price_xtzh".to_string()))? .parse() .map_err(|e| NACError::InvalidResponse(format!("Invalid fragment_price: {}", e)))?, fragmentized_at: Timestamp::from_secs( pool_data["fragmentized_at"] .as_u64() .ok_or(NACError::InvalidResponse("Missing fragmentized_at".to_string()))? ), is_recomposable: pool_data["is_recomposable"] .as_bool() .ok_or(NACError::InvalidResponse("Missing is_recomposable".to_string()))?, }; Ok(pool) } /// 更新资产估值 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// * `valuation` - 新的资产估值 pub async fn update_valuation( &self, certificate_address: &Address, asset_id: AssetId, valuation: AssetValuation, ) -> Result<()> { let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, "valuation": { "value_xtzh": valuation.value_xtzh.to_string(), "valuation_provider": valuation.valuation_provider, "valued_at": valuation.valued_at.as_secs(), "validity_period": valuation.validity_period, }, }); self.client.call("acc721_updateValuation", params).await?; Ok(()) } /// 获取资产估值 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 资产估值 pub async fn get_asset_valuation( &self, certificate_address: &Address, asset_id: AssetId, ) -> Result { let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, }); let response = self.client.call("acc721_getAssetValuation", params).await?; // 解析AssetValuation let val_data = &response["result"]; let valuation = AssetValuation { value_xtzh: val_data["value_xtzh"] .as_str() .ok_or(NACError::InvalidResponse("Missing value_xtzh".to_string()))? .parse() .map_err(|e| NACError::InvalidResponse(format!("Invalid value_xtzh: {}", e)))?, valuation_provider: Address::from_hex( val_data["valuation_provider"] .as_str() .ok_or(NACError::InvalidResponse("Missing valuation_provider".to_string()))? )?, valued_at: Timestamp::from_secs( val_data["valued_at"] .as_u64() .ok_or(NACError::InvalidResponse("Missing valued_at".to_string()))? ), validity_period: val_data["validity_period"] .as_u64() .ok_or(NACError::InvalidResponse("Missing validity_period".to_string()))?, }; Ok(valuation) } /// 获取资产DNA /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 资产DNA pub async fn get_asset_dna( &self, certificate_address: &Address, asset_id: AssetId, ) -> Result { let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, }); let response = self.client.call("acc721_getAssetDNA", params).await?; // 解析AssetDNA let dna_data = &response["result"]; let asset_dna = AssetDNA { dna_hash: Hash::from_hex( dna_data["dna_hash"] .as_str() .ok_or(NACError::InvalidResponse("Missing dna_hash".to_string()))? )?, physical_fingerprint: Hash::from_hex( dna_data["physical_fingerprint"] .as_str() .ok_or(NACError::InvalidResponse("Missing physical_fingerprint".to_string()))? )?, legal_document_hash: Hash::from_hex( dna_data["legal_document_hash"] .as_str() .ok_or(NACError::InvalidResponse("Missing legal_document_hash".to_string()))? )?, generated_at: Timestamp::from_secs( dna_data["generated_at"] .as_u64() .ok_or(NACError::InvalidResponse("Missing generated_at".to_string()))? ), }; Ok(asset_dna) } /// 获取资产元数据 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 资产元数据URI pub async fn get_asset_metadata( &self, certificate_address: &Address, asset_id: AssetId, ) -> Result { let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, }); let response = self.client.call("acc721_getAssetMetadata", params).await?; let metadata_uri = response["result"] .as_str() .ok_or(NACError::InvalidResponse("Missing metadata URI".to_string()))? .to_string(); Ok(metadata_uri) } /// 获取托管信息 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 托管信息 pub async fn get_custody_info( &self, certificate_address: &Address, asset_id: AssetId, ) -> Result { let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, }); let response = self.client.call("acc721_getCustodyInfo", params).await?; // 解析CustodyInfo let custody_data = &response["result"]; let custody_info = CustodyInfo { custodian: Address::from_hex( custody_data["custodian"] .as_str() .ok_or(NACError::InvalidResponse("Missing custodian".to_string()))? )?, custody_start: Timestamp::from_secs( custody_data["custody_start"] .as_u64() .ok_or(NACError::InvalidResponse("Missing custody_start".to_string()))? ), is_active: custody_data["is_active"] .as_bool() .ok_or(NACError::InvalidResponse("Missing is_active".to_string()))?, custody_proof: Hash::from_hex( custody_data["custody_proof"] .as_str() .ok_or(NACError::InvalidResponse("Missing custody_proof".to_string()))? )?, }; Ok(custody_info) } /// 获取保险信息 /// /// # 参数 /// * `certificate_address` - 证书地址 /// * `asset_id` - 资产ID /// /// # 返回 /// 保险信息 pub async fn get_insurance_info( &self, certificate_address: &Address, asset_id: AssetId, ) -> Result { let params = json!({ "certificate_address": certificate_address, "asset_id": asset_id, }); let response = self.client.call("acc721_getInsuranceInfo", params).await?; // 解析InsuranceInfo let insurance_data = &response["result"]; let insurance_info = InsuranceInfo { insurer: Address::from_hex( insurance_data["insurer"] .as_str() .ok_or(NACError::InvalidResponse("Missing insurer".to_string()))? )?, coverage_xtzh: insurance_data["coverage_xtzh"] .as_str() .ok_or(NACError::InvalidResponse("Missing coverage_xtzh".to_string()))? .parse() .map_err(|e| NACError::InvalidResponse(format!("Invalid coverage_xtzh: {}", e)))?, insurance_start: Timestamp::from_secs( insurance_data["insurance_start"] .as_u64() .ok_or(NACError::InvalidResponse("Missing insurance_start".to_string()))? ), insurance_expiry: Timestamp::from_secs( insurance_data["insurance_expiry"] .as_u64() .ok_or(NACError::InvalidResponse("Missing insurance_expiry".to_string()))? ), policy_number: insurance_data["policy_number"] .as_str() .ok_or(NACError::InvalidResponse("Missing policy_number".to_string()))? .to_string(), }; Ok(insurance_info) } } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_acc721_interface() { // 这里只是接口测试,实际需要连接到NAC节点 let client = NRPC3Client::new("https://rpc.newassetchain.io"); let acc721 = ACC721::new(client); // 测试将在实际连接到NAC节点后进行 assert!(true); } }