diff --git a/crates/cast/src/cmd/erc20.rs b/crates/cast/src/cmd/erc20.rs index 9a349ed4e3e8e..9ca03ebd4acd1 100644 --- a/crates/cast/src/cmd/erc20.rs +++ b/crates/cast/src/cmd/erc20.rs @@ -14,6 +14,7 @@ use foundry_cli::{ opts::RpcOpts, utils::{LoadConfig, get_provider}, }; +use foundry_common::shell; #[doc(hidden)] pub use foundry_config::utils::*; @@ -241,7 +242,11 @@ impl Erc20Subcommand { .call() .await?; - sh_println!("{}", format_uint_exp(allowance))? + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&allowance.to_string())?)? + } else { + sh_println!("{}", format_uint_exp(allowance))? + } } Self::Balance { token, owner, block, .. } => { let provider = get_provider(&config)?; @@ -253,7 +258,12 @@ impl Erc20Subcommand { .block(block.unwrap_or_default()) .call() .await?; - sh_println!("{}", format_uint_exp(balance))? + + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&balance.to_string())?)? + } else { + sh_println!("{}", format_uint_exp(balance))? + } } Self::Name { token, block, .. } => { let provider = get_provider(&config)?; @@ -264,7 +274,12 @@ impl Erc20Subcommand { .block(block.unwrap_or_default()) .call() .await?; - sh_println!("{}", name)? + + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&name)?)? + } else { + sh_println!("{}", name)? + } } Self::Symbol { token, block, .. } => { let provider = get_provider(&config)?; @@ -275,7 +290,12 @@ impl Erc20Subcommand { .block(block.unwrap_or_default()) .call() .await?; - sh_println!("{}", symbol)? + + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&symbol)?)? + } else { + sh_println!("{}", symbol)? + } } Self::Decimals { token, block, .. } => { let provider = get_provider(&config)?; @@ -297,7 +317,12 @@ impl Erc20Subcommand { .block(block.unwrap_or_default()) .call() .await?; - sh_println!("{}", format_uint_exp(total_supply))? + + if shell::is_json() { + sh_println!("{}", serde_json::to_string(&total_supply.to_string())?)? + } else { + sh_println!("{}", format_uint_exp(total_supply))? + } } // State-changing Self::Transfer { token, to, amount, send_tx, .. } => { diff --git a/crates/cast/tests/cli/erc20.rs b/crates/cast/tests/cli/erc20.rs index 7390a8af5fded..536cbecca4fae 100644 --- a/crates/cast/tests/cli/erc20.rs +++ b/crates/cast/tests/cli/erc20.rs @@ -263,3 +263,108 @@ forgetest_async!(erc20_burn_success, |prj, cmd| { let total_supply: U256 = output.split_whitespace().next().unwrap().parse().unwrap(); assert_eq!(total_supply, initial_supply - burn_amount); }); + +// tests that `balance` command works correctly with --json flag +forgetest_async!(erc20_balance_json, |prj, cmd| { + let (rpc, token) = setup_token_test(&prj, &mut cmd).await; + + let output = cmd + .cast_fuse() + .args(["--json", "erc20", "balance", &token, anvil_const::ADDR1, "--rpc-url", &rpc]) + .assert_success() + .get_output() + .stdout_lossy(); + + let balance_str: String = serde_json::from_str(&output).expect("valid json string"); + let balance: U256 = balance_str.parse().unwrap(); + assert_eq!(balance, U256::from(1_000_000_000_000_000_000_000u128)); +}); + +// tests that `allowance` command works correctly with --json flag +forgetest_async!(erc20_allowance_json, |prj, cmd| { + let (rpc, token) = setup_token_test(&prj, &mut cmd).await; + + // First approve some tokens + let approve_amount = U256::from(50_000_000_000_000_000_000u128); + cmd.cast_fuse() + .args([ + "erc20", + "approve", + &token, + anvil_const::ADDR2, + &approve_amount.to_string(), + "--rpc-url", + &rpc, + "--private-key", + anvil_const::PK1, + ]) + .assert_success(); + + // Check allowance with JSON flag + let output = cmd + .cast_fuse() + .args([ + "--json", + "erc20", + "allowance", + &token, + anvil_const::ADDR1, + anvil_const::ADDR2, + "--rpc-url", + &rpc, + ]) + .assert_success() + .get_output() + .stdout_lossy(); + + let allowance_str: String = serde_json::from_str(&output).expect("valid json string"); + let allowance: U256 = allowance_str.parse().unwrap(); + assert_eq!(allowance, approve_amount); +}); + +// tests that `name`, `symbol`, `decimals`, and `totalSupply` commands work correctly with --json +// flag +forgetest_async!(erc20_metadata_json, |prj, cmd| { + let (rpc, token) = setup_token_test(&prj, &mut cmd).await; + + // Test name with --json + let output = cmd + .cast_fuse() + .args(["--json", "erc20", "name", &token, "--rpc-url", &rpc]) + .assert_success() + .get_output() + .stdout_lossy(); + let name: String = serde_json::from_str(&output).expect("valid json string"); + assert_eq!(name, "Test Token"); + + // Test symbol with --json + let output = cmd + .cast_fuse() + .args(["--json", "erc20", "symbol", &token, "--rpc-url", &rpc]) + .assert_success() + .get_output() + .stdout_lossy(); + let symbol: String = serde_json::from_str(&output).expect("valid json string"); + assert_eq!(symbol, "TEST"); + + // Test decimals with --json + let output = cmd + .cast_fuse() + .args(["--json", "erc20", "decimals", &token, "--rpc-url", &rpc]) + .assert_success() + .get_output() + .stdout_lossy(); + let decimals: u8 = output.trim().parse().expect("valid number"); + assert_eq!(decimals, 18); + + // Test totalSupply with --json + let output = cmd + .cast_fuse() + .args(["--json", "erc20", "total-supply", &token, "--rpc-url", &rpc]) + .assert_success() + .get_output() + .stdout_lossy(); + let total_supply_str: String = serde_json::from_str(&output).expect("valid json string"); + let total_supply: U256 = total_supply_str.parse().unwrap(); + assert_eq!(total_supply, U256::from(1_000_000_000_000_000_000_000u128)); +});