/ crates / integration / src / adnet_client.rs
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  }