// NAC Lens方法包装层 // 提供高级API,封装nac-sdk的NacLensClient use nac_sdk::client::NacLensClient; use nac_sdk::error::Result as NACResult; use serde_json::{json, Value}; /// NAC Lens包装客户端 /// /// 提供钱包常用的RPC方法包装 pub struct NacLensWrapper { client: NacLensClient, } impl NacLensWrapper { /// 创建新的NAC Lens包装客户端 pub fn new(endpoint: impl Into) -> Self { Self { client: NacLensClient::new(endpoint), } } /// 查询余额 /// /// # Arguments /// /// * `address` - 账户地址(32字节) /// * `asset_id` - 资产ID(可选,默认为XTZH) /// /// # Returns /// /// 余额(u128) pub async fn get_balance(&self, address: &[u8; 32], asset_id: Option<&str>) -> NACResult { let address_hex = hex::encode(address); let asset = asset_id.unwrap_or("xtzh"); let params = json!({ "address": address_hex, "asset_id": asset, }); let result = self.client.call("nac_getBalance", params).await?; // 解析余额 let balance_str = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid balance format".to_string()))?; let balance = u128::from_str_radix(balance_str.trim_start_matches("0x"), 16) .map_err(|e| nac_sdk::error::NACError::InvalidResponse(format!("Failed to parse balance: {}", e)))?; Ok(balance) } /// 查询Nonce /// /// # Arguments /// /// * `address` - 账户地址(32字节) /// /// # Returns /// /// Nonce值(u64) pub async fn get_nonce(&self, address: &[u8; 32]) -> NACResult { let address_hex = hex::encode(address); let params = json!({ "address": address_hex, }); let result = self.client.call("nac_getTransactionCount", params).await?; let nonce_str = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid nonce format".to_string()))?; let nonce = u64::from_str_radix(nonce_str.trim_start_matches("0x"), 16) .map_err(|e| nac_sdk::error::NACError::InvalidResponse(format!("Failed to parse nonce: {}", e)))?; Ok(nonce) } /// 发送原始交易 /// /// # Arguments /// /// * `raw_tx` - 原始交易数据(十六进制字符串) /// /// # Returns /// /// 交易哈希 pub async fn send_raw_transaction(&self, raw_tx: &str) -> NACResult { let params = json!({ "data": raw_tx, }); let result = self.client.call("nac_sendRawTransaction", params).await?; let tx_hash = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid tx hash format".to_string()))? .to_string(); Ok(tx_hash) } /// 查询交易 /// /// # Arguments /// /// * `tx_hash` - 交易哈希 /// /// # Returns /// /// 交易详情(JSON) pub async fn get_transaction(&self, tx_hash: &str) -> NACResult { let params = json!({ "hash": tx_hash, }); self.client.call("nac_getTransactionByHash", params).await } /// 查询交易收据 /// /// # Arguments /// /// * `tx_hash` - 交易哈希 /// /// # Returns /// /// 交易收据(JSON) pub async fn get_transaction_receipt(&self, tx_hash: &str) -> NACResult { let params = json!({ "hash": tx_hash, }); self.client.call("nac_getTransactionReceipt", params).await } /// 查询当前区块号 /// /// # Returns /// /// 区块号(u64) pub async fn get_block_number(&self) -> NACResult { let params = json!({}); let result = self.client.call("nac_blockNumber", params).await?; let block_str = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid block number format".to_string()))?; let block_number = u64::from_str_radix(block_str.trim_start_matches("0x"), 16) .map_err(|e| nac_sdk::error::NACError::InvalidResponse(format!("Failed to parse block number: {}", e)))?; Ok(block_number) } /// 查询区块 /// /// # Arguments /// /// * `block_number` - 区块号 /// * `full_transactions` - 是否包含完整交易 /// /// # Returns /// /// 区块详情(JSON) pub async fn get_block(&self, block_number: u64, full_transactions: bool) -> NACResult { let block_hex = format!("0x{:x}", block_number); let params = json!({ "block": block_hex, "full": full_transactions, }); self.client.call("nac_getBlockByNumber", params).await } /// 估算Gas /// /// # Arguments /// /// * `from` - 发送方地址 /// * `to` - 接收方地址(可选) /// * `value` - 转账金额 /// * `data` - 交易数据(可选) /// /// # Returns /// /// Gas估算值(u64) pub async fn estimate_gas( &self, from: &[u8; 32], to: Option<&[u8; 32]>, value: u128, data: Option<&str>, ) -> NACResult { let from_hex = hex::encode(from); let to_hex = to.map(|addr| hex::encode(addr)); let value_hex = format!("0x{:x}", value); let mut params_obj = json!({ "from": from_hex, "value": value_hex, }); if let Some(to_addr) = to_hex { params_obj["to"] = json!(to_addr); } if let Some(tx_data) = data { params_obj["data"] = json!(tx_data); } let params = json!([params_obj]); let result = self.client.call("nac_estimateGas", params).await?; let gas_str = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid gas format".to_string()))?; let gas = u64::from_str_radix(gas_str.trim_start_matches("0x"), 16) .map_err(|e| nac_sdk::error::NACError::InvalidResponse(format!("Failed to parse gas: {}", e)))?; Ok(gas) } /// 查询Gas价格 /// /// # Returns /// /// Gas价格(u64) pub async fn get_gas_price(&self) -> NACResult { let params = json!({}); let result = self.client.call("nac_gasPrice", params).await?; let price_str = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid gas price format".to_string()))?; let price = u64::from_str_radix(price_str.trim_start_matches("0x"), 16) .map_err(|e| nac_sdk::error::NACError::InvalidResponse(format!("Failed to parse gas price: {}", e)))?; Ok(price) } /// 查询链ID /// /// # Returns /// /// 链ID(u64) pub async fn get_chain_id(&self) -> NACResult { let params = json!({}); let result = self.client.call("nac_chainId", params).await?; let chain_id_str = result.as_str() .ok_or_else(|| nac_sdk::error::NACError::InvalidResponse("Invalid chain ID format".to_string()))?; let chain_id = u64::from_str_radix(chain_id_str.trim_start_matches("0x"), 16) .map_err(|e| nac_sdk::error::NACError::InvalidResponse(format!("Failed to parse chain ID: {}", e)))?; Ok(chain_id) } /// 等待交易确认 /// /// # Arguments /// /// * `tx_hash` - 交易哈希 /// * `confirmations` - 需要的确认数 /// * `timeout_secs` - 超时时间(秒) /// /// # Returns /// /// 交易收据(JSON) pub async fn wait_for_confirmation( &self, tx_hash: &str, confirmations: u64, timeout_secs: u64, ) -> NACResult { use tokio::time::{sleep, Duration}; let start = std::time::Instant::now(); let timeout = Duration::from_secs(timeout_secs); loop { if start.elapsed() > timeout { return Err(nac_sdk::error::NACError::Timeout(format!( "Transaction {} not confirmed after {} seconds", tx_hash, timeout_secs ))); } // 查询交易收据 match self.get_transaction_receipt(tx_hash).await { Ok(receipt) => { // 检查确认数 if let Some(block_number) = receipt.get("blockNumber").and_then(|v| v.as_str()) { let tx_block = u64::from_str_radix(block_number.trim_start_matches("0x"), 16) .unwrap_or(0); let current_block = self.get_block_number().await?; if current_block >= tx_block + confirmations { return Ok(receipt); } } } Err(_) => { // 交易还未被打包,继续等待 } } sleep(Duration::from_secs(2)).await; } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_nac_lens_wrapper_creation() { let wrapper = NacLensWrapper::new("https://rpc.newassetchain.io"); assert!(true); // 创建成功 } }