adnet_client.rs
1 /// Adnet CLI client 2 /// 3 /// Wrapper for executing adnet CLI commands 4 5 use anyhow::{Context, Result}; 6 use serde::{Deserialize, Serialize}; 7 use std::process::{Command, Output}; 8 9 /// Adnet CLI client 10 pub struct AdnetClient { 11 binary_path: String, 12 } 13 14 impl AdnetClient { 15 /// Create a new Adnet CLI client 16 pub fn new(binary_path: String) -> Self { 17 Self { binary_path } 18 } 19 20 /// Create account 21 pub fn create_account(&self, name: &str) -> Result<AccountInfo> { 22 let output = self.execute(&["account", "new", "--name", name])?; 23 self.parse_json_output(&output) 24 } 25 26 /// Get account info 27 pub fn get_account(&self, address: &str) -> Result<AccountInfo> { 28 let output = self.execute(&["account", "get", address])?; 29 self.parse_json_output(&output) 30 } 31 32 /// Transfer tokens 33 pub fn transfer(&self, from: &str, to: &str, amount: u64, token: &str) -> Result<String> { 34 let amount_str = amount.to_string(); 35 let output = self.execute(&[ 36 "account", 37 "transfer", 38 "--from", 39 from, 40 "--to", 41 to, 42 "--amount", 43 &amount_str, 44 "--token", 45 token, 46 ])?; 47 48 self.extract_transaction_id(&output) 49 } 50 51 /// Submit DEX order 52 pub fn trade_order( 53 &self, 54 account: &str, 55 pair: &str, 56 side: &str, 57 amount: &str, 58 price: Option<&str>, 59 ) -> Result<String> { 60 let mut args = vec![ 61 "trade", 62 "order", 63 "--account", 64 account, 65 "--pair", 66 pair, 67 "--side", 68 side, 69 "--amount", 70 amount, 71 ]; 72 73 if let Some(p) = price { 74 args.extend_from_slice(&["--price", p]); 75 } 76 77 let output = self.execute(&args)?; 78 self.extract_order_id(&output) 79 } 80 81 /// Cancel DEX order 82 pub fn trade_cancel(&self, order_id: &str) -> Result<()> { 83 self.execute(&["trade", "cancel", "--order", order_id])?; 84 Ok(()) 85 } 86 87 /// Get validator info 88 pub fn get_validator(&self, address: &str) -> Result<ValidatorInfo> { 89 let output = self.execute(&["validator", "info", address])?; 90 self.parse_json_output(&output) 91 } 92 93 /// Claim rewards 94 pub fn claim_rewards(&self, validator: &str) -> Result<String> { 95 let output = self.execute(&["rewards", "claim", "--validator", validator])?; 96 self.extract_transaction_id(&output) 97 } 98 99 /// Execute a command 100 fn execute(&self, args: &[&str]) -> Result<Output> { 101 let output = Command::new(&self.binary_path) 102 .args(args) 103 .output() 104 .context("Failed to execute adnet command")?; 105 106 if !output.status.success() { 107 let stderr = String::from_utf8_lossy(&output.stderr); 108 anyhow::bail!("Command failed: {}", stderr); 109 } 110 111 Ok(output) 112 } 113 114 /// Parse JSON output 115 fn parse_json_output<T: for<'de> Deserialize<'de>>(&self, output: &Output) -> Result<T> { 116 let stdout = String::from_utf8_lossy(&output.stdout); 117 serde_json::from_str(&stdout).context("Failed to parse JSON output") 118 } 119 120 /// Extract transaction ID from output 121 fn extract_transaction_id(&self, output: &Output) -> Result<String> { 122 let stdout = String::from_utf8_lossy(&output.stdout); 123 // Simple extraction - assumes format "Transaction ID: <id>" 124 stdout 125 .lines() 126 .find(|line| line.contains("Transaction ID:")) 127 .and_then(|line| line.split(':').nth(1)) 128 .map(|id| id.trim().to_string()) 129 .context("Failed to extract transaction ID") 130 } 131 132 /// Extract order ID from output 133 fn extract_order_id(&self, output: &Output) -> Result<String> { 134 let stdout = String::from_utf8_lossy(&output.stdout); 135 // Simple extraction - assumes format "Order ID: <id>" 136 stdout 137 .lines() 138 .find(|line| line.contains("Order ID:")) 139 .and_then(|line| line.split(':').nth(1)) 140 .map(|id| id.trim().to_string()) 141 .context("Failed to extract order ID") 142 } 143 } 144 145 #[derive(Debug, Clone, Serialize, Deserialize)] 146 pub struct AccountInfo { 147 pub address: String, 148 pub balance_ax: u64, 149 pub balance_sax: u64, 150 pub balance_dx: u64, 151 } 152 153 #[derive(Debug, Clone, Serialize, Deserialize)] 154 pub struct ValidatorInfo { 155 pub address: String, 156 pub stake: u64, 157 pub is_active: bool, 158 } 159 160 #[cfg(test)] 161 mod tests { 162 use super::*; 163 164 #[test] 165 fn test_client_creation() { 166 let client = AdnetClient::new("/usr/local/bin/adnet".to_string()); 167 assert_eq!(client.binary_path, "/usr/local/bin/adnet"); 168 } 169 }