//! Synor blockchain CLI. //! //! Command-line interface for interacting with the Synor blockchain. #![allow(dead_code)] use std::path::PathBuf; use clap::{Parser, Subcommand}; mod client; mod commands; mod config; mod output; mod wallet; use crate::client::RpcClient; use crate::config::CliConfig; /// Synor blockchain CLI. #[derive(Parser)] #[command(name = "synor")] #[command(version, about = "Synor blockchain CLI", long_about = None)] struct Cli { /// RPC server URL #[arg( short, long, env = "SYNOR_RPC_URL", default_value = "http://127.0.0.1:16110" )] rpc: String, /// Configuration file path #[arg(short, long)] config: Option, /// Output format (text, json) #[arg(short, long, default_value = "text")] output: String, /// Enable verbose output #[arg(short, long)] verbose: bool, #[command(subcommand)] command: Commands, } #[derive(Subcommand)] enum Commands { // ==================== Node Commands ==================== /// Get node information Info, /// Get node version Version, /// Get sync status SyncStatus, /// Get peer information Peers, // ==================== Block Commands ==================== /// Get block information Block { /// Block hash or height id: String, }, /// Get latest blocks Blocks { /// Number of blocks #[arg(short, long, default_value = "10")] count: usize, }, /// Get current tips Tips, /// Get block count BlockCount, // ==================== Transaction Commands ==================== /// Get transaction information Tx { /// Transaction hash hash: String, }, /// Send transaction Send { /// Recipient address to: String, /// Amount in SYNOR amount: String, /// Fee in SYNOR (optional) #[arg(short, long)] fee: Option, }, /// Get mempool entries Mempool { /// Include transaction details #[arg(short, long)] verbose: bool, }, // ==================== Wallet Commands ==================== /// Wallet operations #[command(subcommand)] Wallet(WalletCommands), /// Get balance Balance { /// Address (uses wallet default if not specified) address: Option, }, /// Get UTXOs Utxos { /// Address address: String, }, // ==================== Address Commands ==================== /// Validate an address ValidateAddress { /// Address to validate address: String, }, /// Decode an address DecodeAddress { /// Address to decode address: String, }, // ==================== Mining Commands ==================== /// Mining operations #[command(subcommand)] Mining(MiningCommands), // ==================== Contract Commands ==================== /// Contract operations #[command(subcommand)] Contract(ContractCommands), // ==================== Governance Commands ==================== /// Governance operations (DAO voting, treasury) #[command(subcommand)] Governance(GovernanceCommands), // ==================== Hosting Commands ==================== /// Deploy web applications to Synor Hosting #[command(subcommand)] Deploy(DeployCommands), // ==================== Network Commands ==================== /// Add a peer AddPeer { /// Peer address (host:port) address: String, }, /// Ban a peer BanPeer { /// Peer address or ID peer: String, }, /// Unban a peer UnbanPeer { /// Peer address or ID peer: String, }, // ==================== DEX Commands ==================== /// Decentralized exchange operations (trading, liquidity) #[command(subcommand)] Dex(commands::dex::DexCommands), // ==================== IBC Commands ==================== /// Inter-Blockchain Communication (cross-chain transfers) #[command(subcommand)] Ibc(commands::ibc::IbcCommands), // ==================== ZK Commands ==================== /// Zero-knowledge proof operations #[command(subcommand)] Zk(commands::zk::ZkCommands), // ==================== Compiler Commands ==================== /// Smart contract compiler tools #[command(subcommand)] Compiler(commands::compiler::CompilerCommands), } #[derive(Subcommand)] enum WalletCommands { /// Create a new wallet (uses Hybrid keys: Ed25519 + Dilithium) Create { /// Wallet name #[arg(short, long, default_value = "default")] name: String, }, /// Import wallet from seed phrase Import { /// Wallet name #[arg(short, long, default_value = "default")] name: String, }, /// Export wallet Export { /// Wallet name #[arg(short, long, default_value = "default")] name: String, }, /// List wallets List, /// Get wallet info Info { /// Wallet name #[arg(short, long, default_value = "default")] name: String, }, /// Generate new address NewAddress { /// Wallet name #[arg(short, long, default_value = "default")] name: String, }, /// List addresses Addresses { /// Wallet name #[arg(short, long, default_value = "default")] name: String, }, } #[derive(Subcommand)] enum MiningCommands { /// Get mining info Info, /// Get block template Template { /// Coinbase address address: String, }, /// Submit a mined block Submit { /// Block hex block: String, }, /// Estimate network hashrate Hashrate, } #[derive(Subcommand)] enum ContractCommands { /// Deploy a contract Deploy { /// Path to WASM file wasm: PathBuf, /// Deployer address (bech32) #[arg(short, long)] deployer: String, /// Constructor arguments (hex) #[arg(short, long)] args: Option, /// Gas limit #[arg(short, long, default_value = "1000000")] gas: u64, }, /// Call a contract method Call { /// Contract ID (hex) contract_id: String, /// Method name method: String, /// Caller address (bech32) #[arg(short, long)] caller: String, /// Arguments (hex) #[arg(short, long)] args: Option, /// Value to send #[arg(short, long, default_value = "0")] value: u64, /// Gas limit #[arg(short, long, default_value = "1000000")] gas: u64, }, /// Get contract code Code { /// Contract ID (hex) contract_id: String, }, /// Get contract storage Storage { /// Contract ID (hex) contract_id: String, /// Storage key (hex) key: String, }, /// Estimate gas for a call EstimateGas { /// Contract ID (hex) contract_id: String, /// Method name method: String, /// Caller address (bech32) #[arg(short, long)] caller: String, /// Arguments (hex) #[arg(short, long)] args: Option, /// Value to send #[arg(short, long, default_value = "0")] value: u64, }, /// Get contract metadata Info { /// Contract ID (hex) contract_id: String, }, } #[derive(Subcommand)] enum GovernanceCommands { /// Get governance info Info, /// Get DAO statistics Stats, /// List proposals Proposals { /// Filter by state (active, pending, passed, defeated, executed) #[arg(short, long)] state: Option, }, /// Get proposal details Proposal { /// Proposal ID (hex) id: String, }, /// Create a proposal CreateProposal { /// Proposer address (bech32) #[arg(short, long)] proposer: String, /// Proposal type (treasury_spend, ecosystem_grant, parameter_change, signaling) #[arg(short = 't', long)] proposal_type: String, /// Proposal title #[arg(long)] title: String, /// Proposal description #[arg(short, long)] description: String, /// Recipient address (for treasury/grant proposals) #[arg(long)] recipient: Option, /// Amount in SYNOR (for treasury/grant proposals) #[arg(long)] amount: Option, /// Parameter name (for parameter_change proposals) #[arg(long)] parameter: Option, /// Old value (for parameter_change proposals) #[arg(long)] old_value: Option, /// New value (for parameter_change proposals) #[arg(long)] new_value: Option, }, /// Vote on a proposal Vote { /// Proposal ID (hex) #[arg(short, long)] proposal_id: String, /// Voter address (bech32) #[arg(short, long)] voter: String, /// Vote choice (yes, no, abstain) #[arg(short, long)] choice: String, /// Optional reason for the vote #[arg(short, long)] reason: Option, }, /// Execute a passed proposal Execute { /// Proposal ID (hex) #[arg(short, long)] proposal_id: String, /// Executor address (bech32) #[arg(short, long)] executor: String, }, /// Get treasury overview Treasury, /// Get treasury pool details TreasuryPool { /// Pool ID (hex) id: String, }, } #[derive(Subcommand)] enum DeployCommands { /// Deploy the current project to Synor Hosting Push { /// Deployment name (defaults to directory name) #[arg(short, long)] name: Option, /// Output directory (defaults to synor.json build.output or "dist") #[arg(short, long)] output: Option, /// Hosting gateway URL #[arg( long, env = "SYNOR_HOSTING_URL", default_value = "http://127.0.0.1:8280" )] gateway: String, /// Skip running the build command #[arg(long)] skip_build: bool, }, /// Initialize synor.json in the current directory Init { /// Deployment name #[arg(short, long)] name: Option, /// Enable SPA mode (fallback to index.html) #[arg(long)] spa: bool, /// Output directory #[arg(short, long)] output: Option, }, /// List deployments List { /// Hosting gateway URL #[arg( long, env = "SYNOR_HOSTING_URL", default_value = "http://127.0.0.1:8280" )] gateway: String, }, /// Delete a deployment Delete { /// Deployment name name: String, /// Hosting gateway URL #[arg( long, env = "SYNOR_HOSTING_URL", default_value = "http://127.0.0.1:8280" )] gateway: String, }, /// Show deployment info Info { /// Deployment name name: String, /// Hosting gateway URL #[arg( long, env = "SYNOR_HOSTING_URL", default_value = "http://127.0.0.1:8280" )] gateway: String, }, } #[tokio::main] async fn main() { let cli = Cli::parse(); // Initialize logging if cli.verbose { tracing_subscriber::fmt() .with_max_level(tracing::Level::DEBUG) .init(); } // Load config let config = CliConfig::load_or_default(cli.config.as_deref()); // Create RPC client let client = RpcClient::new(&cli.rpc); // Set output format let output = output::OutputFormat::from_str(&cli.output); // Execute command let result = match cli.command { // Node commands Commands::Info => commands::node::info(&client, output).await, Commands::Version => commands::node::version(&client, output).await, Commands::SyncStatus => commands::node::sync_status(&client, output).await, Commands::Peers => commands::node::peers(&client, output).await, // Block commands Commands::Block { id } => commands::block::get_block(&client, &id, output).await, Commands::Blocks { count } => commands::block::get_blocks(&client, count, output).await, Commands::Tips => commands::block::get_tips(&client, output).await, Commands::BlockCount => commands::block::get_block_count(&client, output).await, // Transaction commands Commands::Tx { hash } => commands::tx::get_tx(&client, &hash, output).await, Commands::Send { to, amount, fee } => { commands::tx::send(&client, &config, &to, &amount, fee.as_deref(), output).await } Commands::Mempool { verbose } => commands::tx::mempool(&client, verbose, output).await, // Wallet commands Commands::Wallet(cmd) => commands::wallet::handle(&config, cmd, output).await, Commands::Balance { address } => { commands::wallet::balance(&client, &config, address.as_deref(), output).await } Commands::Utxos { address } => commands::wallet::utxos(&client, &address, output).await, // Address commands Commands::ValidateAddress { address } => { commands::address::validate(&address, output).await } Commands::DecodeAddress { address } => commands::address::decode(&address, output).await, // Mining commands Commands::Mining(cmd) => commands::mining::handle(&client, cmd, output).await, // Contract commands Commands::Contract(cmd) => commands::contract::handle(&client, &config, cmd, output).await, // Governance commands Commands::Governance(cmd) => commands::governance::handle(&client, cmd, output).await, // Deploy commands Commands::Deploy(cmd) => match cmd { DeployCommands::Push { name, output: out_dir, gateway, skip_build, } => commands::deploy::deploy(name, out_dir, &gateway, skip_build, output).await, DeployCommands::Init { name, spa, output: out_dir, } => commands::deploy::init(name, spa, out_dir, output), DeployCommands::List { gateway } => commands::deploy::list(&gateway, output).await, DeployCommands::Delete { name, gateway } => { commands::deploy::delete(&name, &gateway, output).await } DeployCommands::Info { name, gateway } => { // TODO: Implement info command output::print_info(&format!("Deployment info for: {}", name)); output::print_kv("Gateway", &gateway); Ok(()) } }, // Network commands Commands::AddPeer { address } => { commands::network::add_peer(&client, &address, output).await } Commands::BanPeer { peer } => commands::network::ban_peer(&client, &peer, output).await, Commands::UnbanPeer { peer } => commands::network::unban_peer(&client, &peer, output).await, // DEX commands Commands::Dex(cmd) => commands::dex::handle(&client, cmd, output).await, // IBC commands Commands::Ibc(cmd) => commands::ibc::handle(&client, cmd, output).await, // ZK commands Commands::Zk(cmd) => commands::zk::handle(&client, cmd, output).await, // Compiler commands Commands::Compiler(cmd) => commands::compiler::handle(&client, cmd, output).await, }; if let Err(e) = result { eprintln!("Error: {}", e); std::process::exit(1); } }