Skip to content

Commit 6c58167

Browse files
authored
feat(cast,common): calldata-decode, abi-decode, and 4byte-decode json flag (#8494)
* add calldata-decode json flag * use print_tokens for calldata-decate, abi-decode, and 4byte-decode * fix clippy
1 parent 2b301a7 commit 6c58167

File tree

4 files changed

+39
-12
lines changed

4 files changed

+39
-12
lines changed

crates/cast/bin/main.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use foundry_cli::{handler, prompt, stdin, utils};
1212
use foundry_common::{
1313
abi::get_event,
1414
ens::{namehash, ProviderEnsExt},
15-
fmt::{format_tokens, format_uint_exp},
15+
fmt::{format_uint_exp, print_tokens},
1616
fs,
1717
selectors::{
1818
decode_calldata, decode_event_topic, decode_function_selector, decode_selectors,
@@ -163,10 +163,9 @@ async fn main() -> Result<()> {
163163
}
164164

165165
// ABI encoding & decoding
166-
CastSubcommand::AbiDecode { sig, calldata, input } => {
166+
CastSubcommand::AbiDecode { sig, calldata, input, json } => {
167167
let tokens = SimpleCast::abi_decode(&sig, &calldata, input)?;
168-
let tokens = format_tokens(&tokens);
169-
tokens.for_each(|t| println!("{t}"));
168+
print_tokens(&tokens, json)
170169
}
171170
CastSubcommand::AbiEncode { sig, packed, args } => {
172171
if !packed {
@@ -175,10 +174,9 @@ async fn main() -> Result<()> {
175174
println!("{}", SimpleCast::abi_encode_packed(&sig, &args)?);
176175
}
177176
}
178-
CastSubcommand::CalldataDecode { sig, calldata } => {
177+
CastSubcommand::CalldataDecode { sig, calldata, json } => {
179178
let tokens = SimpleCast::calldata_decode(&sig, &calldata, true)?;
180-
let tokens = format_tokens(&tokens);
181-
tokens.for_each(|t| println!("{t}"));
179+
print_tokens(&tokens, json)
182180
}
183181
CastSubcommand::CalldataEncode { sig, args } => {
184182
println!("{}", SimpleCast::calldata_encode(sig, &args)?);
@@ -425,7 +423,7 @@ async fn main() -> Result<()> {
425423
println!("{sig}");
426424
}
427425
}
428-
CastSubcommand::FourByteDecode { calldata } => {
426+
CastSubcommand::FourByteDecode { calldata, json } => {
429427
let calldata = stdin::unwrap_line(calldata)?;
430428
let sigs = decode_calldata(&calldata).await?;
431429
sigs.iter().enumerate().for_each(|(i, sig)| println!("{}) \"{sig}\"", i + 1));
@@ -440,9 +438,7 @@ async fn main() -> Result<()> {
440438
};
441439

442440
let tokens = SimpleCast::calldata_decode(sig, &calldata, true)?;
443-
for token in format_tokens(&tokens) {
444-
println!("{token}");
445-
}
441+
print_tokens(&tokens, json)
446442
}
447443
CastSubcommand::FourByteEvent { topic } => {
448444
let topic = stdin::unwrap_line(topic)?;

crates/cast/bin/opts.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,10 @@ pub enum CastSubcommand {
490490

491491
/// The ABI-encoded calldata.
492492
calldata: String,
493+
494+
/// Print the decoded calldata as JSON.
495+
#[arg(long, short, help_heading = "Display options")]
496+
json: bool,
493497
},
494498

495499
/// Decode ABI-encoded input or output data.
@@ -508,6 +512,10 @@ pub enum CastSubcommand {
508512
/// Whether to decode the input or output data.
509513
#[arg(long, short, help_heading = "Decode input data instead of output data")]
510514
input: bool,
515+
516+
/// Print the decoded calldata as JSON.
517+
#[arg(long, short, help_heading = "Display options")]
518+
json: bool,
511519
},
512520

513521
/// ABI encode the given function argument, excluding the selector.
@@ -594,6 +602,10 @@ pub enum CastSubcommand {
594602
FourByteDecode {
595603
/// The ABI-encoded calldata.
596604
calldata: Option<String>,
605+
606+
/// Print the decoded calldata as JSON.
607+
#[arg(long, short, help_heading = "Display options")]
608+
json: bool,
597609
},
598610

599611
/// Get the event signature for a given topic 0 from https://openchain.xyz.

crates/common/fmt/src/dynamic.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,23 @@ pub fn format_tokens(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '
119119
tokens.iter().map(format_token)
120120
}
121121

122+
/// Pretty-prints a slice of tokens using [`format_token_raw`].
123+
pub fn format_tokens_raw(tokens: &[DynSolValue]) -> impl Iterator<Item = String> + '_ {
124+
tokens.iter().map(format_token_raw)
125+
}
126+
127+
/// Prints slice of tokens using [`format_tokens`] or [`format_tokens_raw`] depending on `json`
128+
/// parameter.
129+
pub fn print_tokens(tokens: &[DynSolValue], json: bool) {
130+
if json {
131+
let tokens: Vec<String> = format_tokens_raw(tokens).collect();
132+
println!("{}", serde_json::to_string_pretty(&tokens).unwrap());
133+
} else {
134+
let tokens = format_tokens(tokens);
135+
tokens.for_each(|t| println!("{t}"));
136+
}
137+
}
138+
122139
/// Pretty-prints the given value into a string suitable for user output.
123140
pub fn format_token(value: &DynSolValue) -> String {
124141
DynValueDisplay::new(value, false).to_string()

crates/common/fmt/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ mod console;
44
pub use console::{console_format, ConsoleFmt, FormatSpec};
55

66
mod dynamic;
7-
pub use dynamic::{format_token, format_token_raw, format_tokens, parse_tokens};
7+
pub use dynamic::{
8+
format_token, format_token_raw, format_tokens, format_tokens_raw, parse_tokens, print_tokens,
9+
};
810

911
mod exp;
1012
pub use exp::{format_int_exp, format_uint_exp, to_exp_notation};

0 commit comments

Comments
 (0)