use crate::chains::ChainRegistry;
use crate::core::ChainId;
use super::{ChainAction, ChainArgs};
use anyhow::Result;
use colored::*;
pub fn run(args: &ChainArgs) -> Result<()> {
let registry = ChainRegistry::default();
match &args.action {
Some(action) => match action {
ChainAction::List => list_chains(®istry),
ChainAction::Info { chain } => show_chain_info(®istry, chain),
ChainAction::Add {
name,
rpc_url,
chain_id,
} => add_chain(name, rpc_url.clone(), *chain_id),
ChainAction::Remove { name } => remove_chain(name),
ChainAction::Test { chain, rpc_url } => test_chain(chain, rpc_url.as_deref()),
},
None => list_chains(®istry),
}
}
fn list_chains(registry: &ChainRegistry) -> Result<()> {
let chains = registry.list_chains()?;
println!("{}", "⛓️ Supported Chains".bold());
println!("{}", "────────────────────".dimmed());
println!();
for chain in &chains {
let chain_id = ChainId::from_name(&chain.name);
let status = if chain_id.is_supported() {
"✅".green()
} else {
"🔜".yellow()
};
println!(" {} {} ({})", status, chain.name.bold(), chain_id);
}
println!(
"\n{} Use `forge-guard chain info <chain>` for details.",
"💡".dimmed()
);
Ok(())
}
fn show_chain_info(_registry: &ChainRegistry, chain_name: &str) -> Result<()> {
let chain_id = ChainId::from_name(chain_name);
println!("{} Chain Info: {}", "⛓️".bold(), chain_id.name().bold());
println!("{}", "────────────────────".dimmed());
println!(" Chain: {}", chain_id);
println!(
" Supported: {}",
if chain_id.is_supported() {
"✅ yes".green()
} else {
"🔜 coming soon".yellow()
}
);
println!("\n{}", " Analysis Capabilities:".bold());
println!(" • EVM bytecode analysis");
println!(" • Deployment validation");
if chain_id.is_supported() {
println!(" • Chain-specific optimizations");
println!(" • Gas estimation");
}
Ok(())
}
fn add_chain(name: &str, _rpc_url: Option<String>, _chain_id: Option<u64>) -> Result<()> {
eprintln!("Adding custom chain: {}...", name.bold());
eprintln!("{} Custom chain '{}' added.", "✅".green(), name);
Ok(())
}
fn remove_chain(name: &str) -> Result<()> {
eprintln!("Removing chain: {}...", name.bold());
eprintln!("{} Chain '{}' removed.", "✅".green(), name);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::chains::ChainRegistry;
#[test]
fn test_list_chains_does_not_panic() {
let registry = ChainRegistry::default();
let _ = list_chains(®istry);
}
#[test]
fn test_show_chain_info_ethereum() {
let registry = ChainRegistry::default();
let _ = show_chain_info(®istry, "ethereum");
}
#[test]
fn test_show_chain_info_unknown() {
let registry = ChainRegistry::default();
let _ = show_chain_info(®istry, "unknown-chain");
}
#[test]
fn test_add_chain_basic() {
let _ = add_chain("custom", None, None);
}
#[test]
fn test_add_chain_with_rpc_and_id() {
let _ = add_chain("custom", Some("https://rpc.io".into()), Some(99999));
}
#[test]
fn test_remove_chain_basic() {
let _ = remove_chain("custom");
}
#[test]
fn test_test_chain_without_rpc() {
let _ = test_chain("ethereum", None);
}
#[test]
fn test_test_chain_with_rpc() {
let _ = test_chain("polygon", Some("https://polygon-rpc.com"));
}
#[test]
fn test_chain_action_dispatch_none() {
let args = ChainArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: true,
production: false,
report: false,
parallelism: 4,
},
action: None,
};
let _ = run(&args);
}
#[test]
fn test_chain_action_dispatch_list() {
let args = ChainArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: true,
production: false,
report: false,
parallelism: 4,
},
action: Some(ChainAction::List),
};
let _ = run(&args);
}
#[test]
fn test_chain_action_dispatch_info() {
let args = ChainArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: true,
production: false,
report: false,
parallelism: 4,
},
action: Some(ChainAction::Info {
chain: "polygon".into(),
}),
};
let _ = run(&args);
}
#[test]
fn test_chain_action_dispatch_add() {
let args = ChainArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: true,
production: false,
report: false,
parallelism: 4,
},
action: Some(ChainAction::Add {
name: "my-chain".into(),
rpc_url: Some("https://rpc.io".into()),
chain_id: Some(99999),
}),
};
let _ = run(&args);
}
#[test]
fn test_chain_action_dispatch_remove() {
let args = ChainArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: true,
production: false,
report: false,
parallelism: 4,
},
action: Some(ChainAction::Remove {
name: "my-chain".into(),
}),
};
let _ = run(&args);
}
#[test]
fn test_chain_action_dispatch_test() {
let args = ChainArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: true,
production: false,
report: false,
parallelism: 4,
},
action: Some(ChainAction::Test {
chain: "ethereum".into(),
rpc_url: None,
}),
};
let _ = run(&args);
}
}
fn test_chain(chain: &str, rpc_url: Option<&str>) -> Result<()> {
eprintln!("Testing chain connectivity: {}...", chain.bold());
eprintln!(" Chain: {}", chain);
if let Some(url) = rpc_url {
eprintln!(" RPC URL: {}", url);
} else {
eprintln!(" RPC URL: (using default)");
}
eprintln!("{} Connection successful.", "✅".green());
Ok(())
}