1use clap::Subcommand;
2use serde_json::json;
3
4use crate::client::BackpacClient;
5use crate::config::CairnConfig;
6use crate::errors::CairnError;
7use super::{output_json, Cli};
8
9#[derive(Subcommand, Debug)]
10pub enum RpcCommands {
11 #[command(alias = "ping")]
13 Health,
14
15 Balance {
17 #[arg(long, short)]
19 address: Option<String>,
20 },
21
22 Nonce {
24 #[arg(long, short)]
26 address: Option<String>,
27 },
28
29 Quote,
31}
32
33impl RpcCommands {
34 pub async fn execute(&self, cli: &Cli) -> Result<(), CairnError> {
35 let config = CairnConfig::load();
36 let client = BackpacClient::new(cli.jwt.as_deref(), cli.api_url.as_deref(), cli.worker_url.as_deref());
37
38 let chain = cli.chain.clone().unwrap_or(config.chain);
40 let network = cli.network.clone().unwrap_or(config.network);
41
42 if chain.is_empty() || network.is_empty() {
43 return Err(CairnError::InvalidInput(
44 "Chain and network must be specified via config, env, or flags".to_string(),
45 ));
46 }
47
48 let hostname = format!("{}-{}.{}", chain, network, config.worker_domain);
49
50 match self {
51 RpcCommands::Health => {
52 let body = json!({
54 "jsonrpc": "2.0",
55 "id": 1,
56 "method": "eth_chainId",
57 "params": []
58 });
59
60 let resp = client.rpc_post(&body, None, None, Some(&hostname)).await?;
61 output_json(&resp, &cli.output);
62 }
63 RpcCommands::Balance { address } => {
64 let addr = match address {
65 Some(a) => a.clone(),
66 None => {
67 let claims = client.claims().ok_or(CairnError::Auth("No valid JWT claims found to extract default address".into()))?;
68 claims.get("wallet_address").and_then(|v| v.as_str()).unwrap_or("").to_string()
69 }
70 };
71
72 if addr.is_empty() {
73 return Err(CairnError::InvalidInput("Address could not be resolved".into()));
74 }
75
76 let body = json!({
77 "jsonrpc": "2.0",
78 "id": 1,
79 "method": "eth_getBalance",
80 "params": [addr, "latest"]
81 });
82
83 let resp = client.rpc_post(&body, None, None, Some(&hostname)).await?;
84 output_json(&resp, &cli.output);
85 }
86 RpcCommands::Nonce { address } => {
87 let addr = match address {
88 Some(a) => a.clone(),
89 None => {
90 let claims = client.claims().ok_or(CairnError::Auth("No valid JWT claims found to extract default address".into()))?;
91 claims.get("wallet_address").and_then(|v| v.as_str()).unwrap_or("").to_string()
92 }
93 };
94
95 if addr.is_empty() {
96 return Err(CairnError::InvalidInput("Address could not be resolved".into()));
97 }
98
99 let body = json!({
100 "jsonrpc": "2.0",
101 "id": 1,
102 "method": "eth_getTransactionCount",
103 "params": [addr, "latest"]
104 });
105
106 let resp = client.rpc_post(&body, None, None, Some(&hostname)).await?;
107 output_json(&resp, &cli.output);
108 }
109 RpcCommands::Quote => {
110 let body = json!({
112 "jsonrpc": "2.0",
113 "id": 1,
114 "method": "eth_gasPrice",
115 "params": []
116 });
117
118 let resp = client.rpc_post(&body, None, None, Some(&hostname)).await?;
119
120 output_json(&resp, &cli.output);
123 }
124 }
125
126 Ok(())
127 }
128}