Skip to main content

cast/cmd/
rpc.rs

1use alloy_provider::Provider;
2use clap::Parser;
3use eyre::{Result, WrapErr};
4use foundry_cli::{
5    json::{print_json_success, print_json_value_or_scalar},
6    opts::RpcOpts,
7    utils,
8    utils::LoadConfig,
9};
10use foundry_common::shell;
11use serde_json::{Value, value::RawValue};
12
13/// CLI arguments for `cast rpc`.
14#[derive(Clone, Debug, Parser)]
15pub struct RpcArgs {
16    /// RPC method name
17    method: String,
18
19    /// RPC parameters
20    ///
21    /// Interpreted as JSON:
22    ///
23    /// cast rpc eth_getBlockByNumber 0x123 false
24    /// => {"method": "eth_getBlockByNumber", "params": ["0x123", false] ... }
25    params: Vec<String>,
26
27    /// Send raw JSON parameters
28    ///
29    /// The first param will be interpreted as a raw JSON array of params.
30    /// If no params are given, stdin will be used. For example:
31    ///
32    /// cast rpc eth_getBlockByNumber '["0x123", false]' --raw
33    ///     => {"method": "eth_getBlockByNumber", "params": ["0x123", false] ... }
34    #[arg(long, short = 'w')]
35    raw: bool,
36
37    #[command(flatten)]
38    rpc: RpcOpts,
39}
40
41impl RpcArgs {
42    pub async fn run(self) -> Result<()> {
43        let Self { raw, method, params, rpc } = self;
44        let config = rpc.load_config()?;
45
46        let params = if !raw {
47            // Arguments that are not valid JSON, such as `0x123`, are passed as strings.
48            Value::Array(
49                params
50                    .into_iter()
51                    .map(|param| serde_json::from_str(&param).unwrap_or(Value::String(param)))
52                    .collect(),
53            )
54        } else if params.is_empty() {
55            serde_json::Deserializer::from_reader(std::io::stdin())
56                .into_iter()
57                .next()
58                .transpose()?
59                .ok_or_else(|| eyre::format_err!("Empty JSON parameters"))?
60        } else {
61            serde_json::from_str(&params.join(" ")).wrap_err("invalid raw JSON parameters")?
62        };
63
64        let result = utils::get_provider(&config)?
65            .raw_request::<_, Box<RawValue>>(method.into(), params)
66            .await?;
67
68        // Print the result as the node sent it, which avoids a `Value` tree of large results.
69        // Without whitespace or escapes, a `Value` would serialize it back to the same text.
70        if result.get().contains([' ', '\t', '\n', '\r', '\\']) {
71            let result = serde_json::from_str::<Value>(result.get())?;
72            return print_json_value_or_scalar(result.to_string());
73        }
74        if shell::is_json() {
75            print_json_success(&*result)
76        } else {
77            sh_println!("{}", result.get())?;
78            Ok(())
79        }
80    }
81}