cast/cmd/
rpc.rs

1use crate::Cast;
2use clap::Parser;
3use eyre::Result;
4use foundry_cli::{opts::RpcOpts, utils, utils::LoadConfig};
5use itertools::Itertools;
6
7/// CLI arguments for `cast rpc`.
8#[derive(Clone, Debug, Parser)]
9pub struct RpcArgs {
10    /// RPC method name
11    method: String,
12
13    /// RPC parameters
14    ///
15    /// Interpreted as JSON:
16    ///
17    /// cast rpc eth_getBlockByNumber 0x123 false
18    /// => {"method": "eth_getBlockByNumber", "params": ["0x123", false] ... }
19    params: Vec<String>,
20
21    /// Send raw JSON parameters
22    ///
23    /// The first param will be interpreted as a raw JSON array of params.
24    /// If no params are given, stdin will be used. For example:
25    ///
26    /// cast rpc eth_getBlockByNumber '["0x123", false]' --raw
27    ///     => {"method": "eth_getBlockByNumber", "params": ["0x123", false] ... }
28    #[arg(long, short = 'w')]
29    raw: bool,
30
31    #[command(flatten)]
32    rpc: RpcOpts,
33}
34
35impl RpcArgs {
36    pub async fn run(self) -> Result<()> {
37        let Self { raw, method, params, rpc } = self;
38
39        let config = rpc.load_config()?;
40        let provider = utils::get_provider(&config)?;
41
42        let params = if raw {
43            if params.is_empty() {
44                serde_json::Deserializer::from_reader(std::io::stdin())
45                    .into_iter()
46                    .next()
47                    .transpose()?
48                    .ok_or_else(|| eyre::format_err!("Empty JSON parameters"))?
49            } else {
50                value_or_string(params.into_iter().join(" "))
51            }
52        } else {
53            serde_json::Value::Array(params.into_iter().map(value_or_string).collect())
54        };
55        sh_println!("{}", Cast::new(provider).rpc(&method, params).await?)?;
56        Ok(())
57    }
58}
59
60fn value_or_string(value: String) -> serde_json::Value {
61    serde_json::from_str(&value).unwrap_or(serde_json::Value::String(value))
62}