diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..568abd4 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,19 @@ +pub mod account; +pub mod account_factory; +pub mod address_book; +pub mod block_id; +pub mod casm; +pub mod chain_id; +pub mod compiler; +pub mod decode; +pub mod error; +pub mod fee; +pub mod hd_path; +pub mod network; +pub mod path; +pub mod profile; +pub mod provider; +pub mod signer; +pub mod subcommands; +pub mod utils; +pub mod verbosity; diff --git a/src/main.rs b/src/main.rs index c06275c..e4dd241 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,7 @@ -use anyhow::Result; -use clap::{CommandFactory, Parser, Subcommand}; +use clap::Parser; use colored::Colorize; -use crate::{provider::ProviderArgs, subcommands::*}; +use crate::utils::*; mod account; mod account_factory; @@ -24,137 +23,6 @@ mod subcommands; mod utils; mod verbosity; -pub(crate) const JSON_RPC_VERSION: &str = "0.7.1"; - -const VERSION_STRING: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("VERGEN_GIT_SHA"), ")"); -const VERSION_STRING_VERBOSE: &str = concat!( - env!("CARGO_PKG_VERSION"), - " (", - env!("VERGEN_GIT_SHA"), - ")\n", - "JSON-RPC version: 0.7.1" -); - -#[derive(Debug, Parser)] -#[clap(author, about)] -struct Cli { - #[clap(subcommand)] - command: Option, - #[clap(long = "version", short = 'V', help = "Print version info and exit")] - version: bool, - #[clap( - long = "verbose", - short = 'v', - help = "Use verbose output (currently only applied to version)" - )] - verbose: bool, -} - -#[derive(Debug, Subcommand)] -enum Subcommands { - // - // Local utilities - // - #[clap(about = "Calculate selector from name")] - Selector(Selector), - #[clap(about = "Calculate class hash from any contract artifacts (Sierra, casm, legacy)")] - ClassHash(ClassHash), - #[clap(about = "Extract contract ABI from a class artifact (Sierra or legacy)")] - Abi(Abi), - #[clap(about = "Encode string into felt with the Cairo short string representation")] - ToCairoString(ToCairoString), - #[clap(about = "Decode string from felt with the Cairo short string representation")] - ParseCairoString(ParseCairoString), - #[clap(about = "Print the montgomery representation of a field element")] - Mont(Mont), - // - // JSON-RPC query client - // - #[clap(about = "Call contract functions without sending transactions")] - Call(Call), - #[clap(alias = "tx", about = "Get Starknet transaction by hash")] - Transaction(Transaction), - #[clap(alias = "bn", about = "Get latest block number")] - BlockNumber(BlockNumber), - #[clap(about = "Get latest block hash")] - BlockHash(BlockHash), - #[clap(about = "Get Starknet block")] - Block(Block), - #[clap(about = "Get Starknet block timestamp only")] - BlockTime(BlockTime), - #[clap(about = "Get state update from a certain block")] - StateUpdate(StateUpdate), - #[clap(about = "Get all traces from a certain block")] - BlockTraces(BlockTraces), - #[clap( - aliases = ["tx-status", "transaction-status"], - about = "Get transaction status by hash" - )] - Status(TransactionStatus), - #[clap( - aliases = ["tx-receipt", "transaction-receipt"], - about = "Get transaction receipt by hash" - )] - Receipt(TransactionReceipt), - #[clap(about = "Get transaction trace by hash")] - Trace(TransactionTrace), - #[clap(about = "Get Starknet network ID")] - ChainId(ChainId), - #[clap(about = "Get native gas token (currently ETH) balance")] - Balance(Balance), - #[clap(about = "Get nonce for a certain contract")] - Nonce(Nonce), - #[clap(about = "Get storage value for a slot at a contract")] - Storage(Storage), - #[clap(about = "Get contract class hash deployed at a certain address")] - ClassHashAt(ClassHashAt), - #[clap(about = "Get contract class by hash")] - ClassByHash(ClassByHash), - #[clap(about = "Get contract class deployed at a certain address")] - ClassAt(ClassAt), - #[clap(about = "Get node syncing status")] - Syncing(Syncing), - #[clap(about = "Get node spec version")] - SpecVersion(SpecVersion), - // - // Signer management - // - #[clap(about = "Signer management commands")] - Signer(Signer), - #[clap(about = "Shortcut for `starkli signer ledger`")] - Ledger(crate::subcommands::signer::ledger::Ledger), - #[clap(aliases = ["erc2645"], about = "EIP-2645 helper commands")] - Eip2645(Eip2645), - // - // Account management - // - #[clap(about = "Account management commands")] - Account(Account), - // - // Sending out transactions - // - #[clap(about = "Send an invoke transaction from an account contract")] - Invoke(Invoke), - #[clap(about = "Declare a contract class")] - Declare(Declare), - #[clap(about = "Deploy contract via the Universal Deployer Contract")] - Deploy(Deploy), - // - // Misc - // - #[clap(about = "Generate shell completions script")] - Completions(Completions), - // - // Experimental - // - #[clap( - about = "Experimental commands for fun and profit", - long_about = "Experimental new commands that are shipped with no stability guarantee. \ - They might break or be removed anytime." - )] - Lab(Lab), -} - #[tokio::main] async fn main() { if let Err(err) = run_command(Cli::parse()).await { @@ -162,58 +30,3 @@ async fn main() { std::process::exit(1); } } - -async fn run_command(cli: Cli) -> Result<()> { - match (cli.version, cli.command) { - (false, None) => Ok(Cli::command().print_help()?), - (true, _) => { - println!( - "{}", - if cli.verbose { - VERSION_STRING_VERBOSE - } else { - VERSION_STRING - } - ); - - Ok(()) - } - (false, Some(command)) => match command { - Subcommands::Selector(cmd) => cmd.run(), - Subcommands::ClassHash(cmd) => cmd.run(), - Subcommands::Abi(cmd) => cmd.run(), - Subcommands::ToCairoString(cmd) => cmd.run(), - Subcommands::ParseCairoString(cmd) => cmd.run(), - Subcommands::Mont(cmd) => cmd.run(), - Subcommands::Call(cmd) => cmd.run().await, - Subcommands::Transaction(cmd) => cmd.run().await, - Subcommands::BlockNumber(cmd) => cmd.run().await, - Subcommands::BlockHash(cmd) => cmd.run().await, - Subcommands::Block(cmd) => cmd.run().await, - Subcommands::BlockTime(cmd) => cmd.run().await, - Subcommands::StateUpdate(cmd) => cmd.run().await, - Subcommands::BlockTraces(cmd) => cmd.run().await, - Subcommands::Status(cmd) => cmd.run().await, - Subcommands::Receipt(cmd) => cmd.run().await, - Subcommands::Trace(cmd) => cmd.run().await, - Subcommands::ChainId(cmd) => cmd.run().await, - Subcommands::Balance(cmd) => cmd.run().await, - Subcommands::Nonce(cmd) => cmd.run().await, - Subcommands::Storage(cmd) => cmd.run().await, - Subcommands::ClassHashAt(cmd) => cmd.run().await, - Subcommands::ClassByHash(cmd) => cmd.run().await, - Subcommands::ClassAt(cmd) => cmd.run().await, - Subcommands::Syncing(cmd) => cmd.run().await, - Subcommands::SpecVersion(cmd) => cmd.run().await, - Subcommands::Signer(cmd) => cmd.run().await, - Subcommands::Ledger(cmd) => cmd.run().await, - Subcommands::Eip2645(cmd) => cmd.run(), - Subcommands::Account(cmd) => cmd.run().await, - Subcommands::Invoke(cmd) => cmd.run().await, - Subcommands::Declare(cmd) => cmd.run().await, - Subcommands::Deploy(cmd) => cmd.run().await, - Subcommands::Completions(cmd) => cmd.run(), - Subcommands::Lab(cmd) => cmd.run(), - }, - } -} diff --git a/src/provider.rs b/src/provider.rs index 7833611..9bd01a1 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -19,7 +19,7 @@ use crate::{ profile::{ FreeProviderVendor, NetworkProvider, Profile, Profiles, RpcProvider, DEFAULT_PROFILE_NAME, }, - JSON_RPC_VERSION, + utils::JSON_RPC_VERSION, }; const CHAIN_ID_MAINNET: Felt = short_string!("SN_MAIN"); diff --git a/src/subcommands/account/deploy.rs b/src/subcommands/account/deploy.rs index ff11716..5e502a7 100644 --- a/src/subcommands/account/deploy.rs +++ b/src/subcommands/account/deploy.rs @@ -20,10 +20,10 @@ use crate::{ error::account_factory_error_mapper, fee::{FeeArgs, FeeSetting, FeeToken, TokenFeeSetting}, path::ExpandedPathbufParser, + provider::ProviderArgs, signer::SignerArgs, utils::{felt_to_bigdecimal, print_colored_json, watch_tx}, verbosity::VerbosityArgs, - ProviderArgs, }; #[derive(Debug, Parser)] @@ -52,6 +52,8 @@ pub struct Deploy { file: PathBuf, #[clap(flatten)] verbosity: VerbosityArgs, + #[clap(long)] + skip_manual_confirmation: bool, } #[derive(Debug, Clone, Copy)] @@ -246,7 +248,12 @@ impl Deploy { return Ok(()); } - fee_prompt(fee_type, target_deployment_address, FeeToken::Eth)?; + fee_prompt( + fee_type, + target_deployment_address, + FeeToken::Eth, + self.skip_manual_confirmation, + )?; account_deployment.send().await } @@ -368,7 +375,12 @@ impl Deploy { return Ok(()); } - fee_prompt(fee_type, target_deployment_address, FeeToken::Strk)?; + fee_prompt( + fee_type, + target_deployment_address, + FeeToken::Strk, + self.skip_manual_confirmation, + )?; account_deployment.send().await } @@ -420,7 +432,12 @@ impl Deploy { } } -fn fee_prompt(fee_type: MaxFeeType, deployed_address: Felt, fee_token: FeeToken) -> Result<()> { +fn fee_prompt( + fee_type: MaxFeeType, + deployed_address: Felt, + fee_token: FeeToken, + skip_manual_confirmation: bool, +) -> Result<()> { match fee_type { MaxFeeType::Manual { max_fee } => { eprintln!( @@ -453,9 +470,10 @@ fn fee_prompt(fee_type: MaxFeeType, deployed_address: Felt, fee_token: FeeToken) format!("{:#064x}", deployed_address).bright_yellow() ); - // TODO: add flag for skipping this manual confirmation step - eprint!("Press [ENTER] once you've funded the address."); - std::io::stdin().read_line(&mut String::new())?; + if !skip_manual_confirmation { + eprint!("Press [ENTER] once you've funded the address."); + std::io::stdin().read_line(&mut String::new())?; + } Ok(()) } diff --git a/src/subcommands/account/fetch.rs b/src/subcommands/account/fetch.rs index f464b2b..82d1e38 100644 --- a/src/subcommands/account/fetch.rs +++ b/src/subcommands/account/fetch.rs @@ -16,8 +16,8 @@ use crate::{ BraavosMultisigConfig, BraavosSigner, BraavosStarkSigner, DeployedStatus, DeploymentStatus, OzAccountConfig, KNOWN_ACCOUNT_CLASSES, }, + provider::ProviderArgs, verbosity::VerbosityArgs, - ProviderArgs, }; #[derive(Debug, Parser)] diff --git a/src/subcommands/balance.rs b/src/subcommands/balance.rs index c7917ac..c0689c3 100644 --- a/src/subcommands/balance.rs +++ b/src/subcommands/balance.rs @@ -11,7 +11,8 @@ use starknet::{ }; use crate::{ - address_book::AddressBookResolver, decode::FeltDecoder, verbosity::VerbosityArgs, ProviderArgs, + address_book::AddressBookResolver, decode::FeltDecoder, provider::ProviderArgs, + verbosity::VerbosityArgs, }; /// The default ETH address: 0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7. diff --git a/src/subcommands/block.rs b/src/subcommands/block.rs index 31bc2ed..c322277 100644 --- a/src/subcommands/block.rs +++ b/src/subcommands/block.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::BlockId, providers::Provider}; -use crate::{block_id::BlockIdParser, verbosity::VerbosityArgs, ProviderArgs}; +use crate::{block_id::BlockIdParser, provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct Block { diff --git a/src/subcommands/block_hash.rs b/src/subcommands/block_hash.rs index 6c06aa4..557b939 100644 --- a/src/subcommands/block_hash.rs +++ b/src/subcommands/block_hash.rs @@ -2,7 +2,7 @@ use anyhow::Result; use clap::Parser; use starknet::providers::Provider; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct BlockHash { diff --git a/src/subcommands/block_number.rs b/src/subcommands/block_number.rs index 4846592..4fa84f4 100644 --- a/src/subcommands/block_number.rs +++ b/src/subcommands/block_number.rs @@ -2,7 +2,7 @@ use anyhow::Result; use clap::Parser; use starknet::providers::Provider; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct BlockNumber { diff --git a/src/subcommands/block_time.rs b/src/subcommands/block_time.rs index a159f1d..6b63e35 100644 --- a/src/subcommands/block_time.rs +++ b/src/subcommands/block_time.rs @@ -6,7 +6,7 @@ use starknet::{ providers::Provider, }; -use crate::{block_id::BlockIdParser, verbosity::VerbosityArgs, ProviderArgs}; +use crate::{block_id::BlockIdParser, provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct BlockTime { diff --git a/src/subcommands/block_traces.rs b/src/subcommands/block_traces.rs index 139b20b..1eb36bd 100644 --- a/src/subcommands/block_traces.rs +++ b/src/subcommands/block_traces.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::BlockId, providers::Provider}; -use crate::{block_id::BlockIdParser, verbosity::VerbosityArgs, ProviderArgs}; +use crate::{block_id::BlockIdParser, provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct BlockTraces { diff --git a/src/subcommands/call.rs b/src/subcommands/call.rs index 14e83c4..6c45011 100644 --- a/src/subcommands/call.rs +++ b/src/subcommands/call.rs @@ -6,10 +6,11 @@ use starknet::{ core::types::{BlockId, FunctionCall}, providers::Provider, }; +use starknet_crypto::Felt; use crate::{ address_book::AddressBookResolver, block_id::BlockIdParser, decode::FeltDecoder, - error::provider_error_mapper, verbosity::VerbosityArgs, ProviderArgs, + error::provider_error_mapper, provider::ProviderArgs, verbosity::VerbosityArgs, }; #[derive(Debug, Parser)] @@ -36,7 +37,11 @@ pub struct Call { impl Call { pub async fn run(self) -> Result<()> { self.verbosity.setup_logging(); + let _ = self.call().await?; + Ok(()) + } + pub async fn call(self) -> Result> { let provider = Arc::new(self.provider.into_provider()?); let felt_decoder = FeltDecoder::new(AddressBookResolver::new(provider.clone())); @@ -83,7 +88,6 @@ impl Call { println!("]"); } - - Ok(()) + Ok(result) } } diff --git a/src/subcommands/chain_id.rs b/src/subcommands/chain_id.rs index 076d4cc..4773382 100644 --- a/src/subcommands/chain_id.rs +++ b/src/subcommands/chain_id.rs @@ -2,7 +2,7 @@ use anyhow::Result; use clap::Parser; use starknet::{core::utils::parse_cairo_short_string, providers::Provider}; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct ChainId { diff --git a/src/subcommands/class_at.rs b/src/subcommands/class_at.rs index 9da1b09..0f9afc4 100644 --- a/src/subcommands/class_at.rs +++ b/src/subcommands/class_at.rs @@ -6,9 +6,9 @@ use starknet::{ }; use crate::{ + provider::ProviderArgs, utils::{parse_compressed_legacy_class, parse_flattened_sierra_class, print_colored_json}, verbosity::VerbosityArgs, - ProviderArgs, }; #[derive(Debug, Parser)] diff --git a/src/subcommands/class_by_hash.rs b/src/subcommands/class_by_hash.rs index b02064e..859847b 100644 --- a/src/subcommands/class_by_hash.rs +++ b/src/subcommands/class_by_hash.rs @@ -6,9 +6,9 @@ use starknet::{ }; use crate::{ + provider::ProviderArgs, utils::{parse_compressed_legacy_class, parse_flattened_sierra_class, print_colored_json}, verbosity::VerbosityArgs, - ProviderArgs, }; #[derive(Debug, Parser)] diff --git a/src/subcommands/class_hash_at.rs b/src/subcommands/class_hash_at.rs index 0e65bce..7fa433e 100644 --- a/src/subcommands/class_hash_at.rs +++ b/src/subcommands/class_hash_at.rs @@ -5,7 +5,7 @@ use starknet::{ providers::Provider, }; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct ClassHashAt { diff --git a/src/subcommands/completions.rs b/src/subcommands/completions.rs index 7630641..7d75ecd 100644 --- a/src/subcommands/completions.rs +++ b/src/subcommands/completions.rs @@ -2,7 +2,7 @@ use anyhow::Result; use clap::{CommandFactory, Parser}; use clap_complete::{generate, Shell}; -use crate::Cli; +use crate::utils::Cli; #[derive(Debug, Parser)] pub struct Completions { diff --git a/src/subcommands/declare.rs b/src/subcommands/declare.rs index 4b9bb90..0550cfb 100644 --- a/src/subcommands/declare.rs +++ b/src/subcommands/declare.rs @@ -19,9 +19,9 @@ use crate::{ error::account_error_mapper, fee::{FeeArgs, FeeSetting, TokenFeeSetting}, path::ExpandedPathbufParser, + provider::ProviderArgs, utils::{felt_to_bigdecimal, parse_compressed_legacy_class, print_colored_json, watch_tx}, verbosity::VerbosityArgs, - ProviderArgs, }; #[derive(Debug, Parser)] diff --git a/src/subcommands/deploy.rs b/src/subcommands/deploy.rs index 2b51cb9..66a25b2 100644 --- a/src/subcommands/deploy.rs +++ b/src/subcommands/deploy.rs @@ -11,9 +11,9 @@ use crate::{ decode::FeltDecoder, error::account_error_mapper, fee::{FeeArgs, FeeSetting, TokenFeeSetting}, + provider::ProviderArgs, utils::{felt_to_bigdecimal, print_colored_json, watch_tx}, verbosity::VerbosityArgs, - ProviderArgs, }; /// The default UDC address: 0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf. diff --git a/src/subcommands/invoke.rs b/src/subcommands/invoke.rs index 7ef55bd..952ffd6 100644 --- a/src/subcommands/invoke.rs +++ b/src/subcommands/invoke.rs @@ -14,9 +14,9 @@ use crate::{ decode::FeltDecoder, error::account_error_mapper, fee::{FeeArgs, FeeSetting, TokenFeeSetting}, + provider::ProviderArgs, utils::{felt_to_bigdecimal, print_colored_json, watch_tx}, verbosity::VerbosityArgs, - ProviderArgs, }; #[derive(Debug, Parser)] diff --git a/src/subcommands/nonce.rs b/src/subcommands/nonce.rs index 8640e70..68d78e9 100644 --- a/src/subcommands/nonce.rs +++ b/src/subcommands/nonce.rs @@ -5,7 +5,7 @@ use starknet::{ providers::Provider, }; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct Nonce { diff --git a/src/subcommands/spec_version.rs b/src/subcommands/spec_version.rs index 8e9c0aa..278f948 100644 --- a/src/subcommands/spec_version.rs +++ b/src/subcommands/spec_version.rs @@ -2,7 +2,7 @@ use anyhow::Result; use clap::Parser; use starknet::providers::Provider; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct SpecVersion { diff --git a/src/subcommands/state_update.rs b/src/subcommands/state_update.rs index 31c209f..5dd0398 100644 --- a/src/subcommands/state_update.rs +++ b/src/subcommands/state_update.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::BlockId, providers::Provider}; -use crate::{block_id::BlockIdParser, verbosity::VerbosityArgs, ProviderArgs}; +use crate::{block_id::BlockIdParser, provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct StateUpdate { diff --git a/src/subcommands/storage.rs b/src/subcommands/storage.rs index 0f1e763..b54236d 100644 --- a/src/subcommands/storage.rs +++ b/src/subcommands/storage.rs @@ -8,7 +8,8 @@ use starknet::{ }; use crate::{ - address_book::AddressBookResolver, decode::FeltDecoder, verbosity::VerbosityArgs, ProviderArgs, + address_book::AddressBookResolver, decode::FeltDecoder, provider::ProviderArgs, + verbosity::VerbosityArgs, }; #[derive(Debug, Parser)] diff --git a/src/subcommands/syncing.rs b/src/subcommands/syncing.rs index 245210c..e921c92 100644 --- a/src/subcommands/syncing.rs +++ b/src/subcommands/syncing.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::SyncStatusType, providers::Provider}; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct Syncing { diff --git a/src/subcommands/transaction.rs b/src/subcommands/transaction.rs index a4f9786..9a1c7a1 100644 --- a/src/subcommands/transaction.rs +++ b/src/subcommands/transaction.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::Felt, providers::Provider}; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct Transaction { diff --git a/src/subcommands/transaction_receipt.rs b/src/subcommands/transaction_receipt.rs index beec213..997e0f1 100644 --- a/src/subcommands/transaction_receipt.rs +++ b/src/subcommands/transaction_receipt.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::Felt, providers::Provider}; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct TransactionReceipt { diff --git a/src/subcommands/transaction_status.rs b/src/subcommands/transaction_status.rs index 6100831..eaa4360 100644 --- a/src/subcommands/transaction_status.rs +++ b/src/subcommands/transaction_status.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::Felt, providers::Provider}; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct TransactionStatus { diff --git a/src/subcommands/transaction_trace.rs b/src/subcommands/transaction_trace.rs index ca822e4..e3c496c 100644 --- a/src/subcommands/transaction_trace.rs +++ b/src/subcommands/transaction_trace.rs @@ -3,7 +3,7 @@ use clap::Parser; use colored_json::{ColorMode, Output}; use starknet::{core::types::Felt, providers::Provider}; -use crate::{verbosity::VerbosityArgs, ProviderArgs}; +use crate::{provider::ProviderArgs, verbosity::VerbosityArgs}; #[derive(Debug, Parser)] pub struct TransactionTrace { diff --git a/src/utils.rs b/src/utils.rs index 71db3b2..1ba6569 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,9 @@ use std::{io::Read, time::Duration}; +use crate::subcommands::*; use anyhow::Result; use bigdecimal::{BigDecimal, Zero}; +use clap::{CommandFactory, Parser, Subcommand}; use colored::Colorize; use colored_json::{ColorMode, ColoredFormatter, Output}; use flate2::read::GzDecoder; @@ -25,6 +27,193 @@ use starknet::{ providers::{Provider, ProviderError}, }; +pub const JSON_RPC_VERSION: &str = "0.7.1"; + +pub const VERSION_STRING: &str = + concat!(env!("CARGO_PKG_VERSION"), " (", env!("VERGEN_GIT_SHA"), ")"); +pub const VERSION_STRING_VERBOSE: &str = concat!( + env!("CARGO_PKG_VERSION"), + " (", + env!("VERGEN_GIT_SHA"), + ")\n", + "JSON-RPC version: 0.7.1" +); + +#[derive(Debug, Parser)] +#[clap(author, about)] +pub struct Cli { + #[clap(subcommand)] + pub command: Option, + #[clap(long = "version", short = 'V', help = "Print version info and exit")] + pub version: bool, + #[clap( + long = "verbose", + short = 'v', + help = "Use verbose output (currently only applied to version)" + )] + pub verbose: bool, +} + +#[derive(Debug, Subcommand)] +pub enum Subcommands { + // + // Local utilities + // + #[clap(about = "Calculate selector from name")] + Selector(Selector), + #[clap(about = "Calculate class hash from any contract artifacts (Sierra, casm, legacy)")] + ClassHash(ClassHash), + #[clap(about = "Extract contract ABI from a class artifact (Sierra or legacy)")] + Abi(Abi), + #[clap(about = "Encode string into felt with the Cairo short string representation")] + ToCairoString(ToCairoString), + #[clap(about = "Decode string from felt with the Cairo short string representation")] + ParseCairoString(ParseCairoString), + #[clap(about = "Print the montgomery representation of a field element")] + Mont(Mont), + // + // JSON-RPC query client + // + #[clap(about = "Call contract functions without sending transactions")] + Call(Call), + #[clap(alias = "tx", about = "Get Starknet transaction by hash")] + Transaction(Transaction), + #[clap(alias = "bn", about = "Get latest block number")] + BlockNumber(BlockNumber), + #[clap(about = "Get latest block hash")] + BlockHash(BlockHash), + #[clap(about = "Get Starknet block")] + Block(Block), + #[clap(about = "Get Starknet block timestamp only")] + BlockTime(BlockTime), + #[clap(about = "Get state update from a certain block")] + StateUpdate(StateUpdate), + #[clap(about = "Get all traces from a certain block")] + BlockTraces(BlockTraces), + #[clap( + aliases = ["tx-status", "transaction-status"], + about = "Get transaction status by hash" + )] + Status(TransactionStatus), + #[clap( + aliases = ["tx-receipt", "transaction-receipt"], + about = "Get transaction receipt by hash" + )] + Receipt(TransactionReceipt), + #[clap(about = "Get transaction trace by hash")] + Trace(TransactionTrace), + #[clap(about = "Get Starknet network ID")] + ChainId(ChainId), + #[clap(about = "Get native gas token (currently ETH) balance")] + Balance(Balance), + #[clap(about = "Get nonce for a certain contract")] + Nonce(Nonce), + #[clap(about = "Get storage value for a slot at a contract")] + Storage(Storage), + #[clap(about = "Get contract class hash deployed at a certain address")] + ClassHashAt(ClassHashAt), + #[clap(about = "Get contract class by hash")] + ClassByHash(ClassByHash), + #[clap(about = "Get contract class deployed at a certain address")] + ClassAt(ClassAt), + #[clap(about = "Get node syncing status")] + Syncing(Syncing), + #[clap(about = "Get node spec version")] + SpecVersion(SpecVersion), + // + // Signer management + // + #[clap(about = "Signer management commands")] + Signer(Signer), + #[clap(about = "Shortcut for `starkli signer ledger`")] + Ledger(crate::subcommands::signer::ledger::Ledger), + #[clap(aliases = ["erc2645"], about = "EIP-2645 helper commands")] + Eip2645(Eip2645), + // + // Account management + // + #[clap(about = "Account management commands")] + Account(Account), + // + // Sending out transactions + // + #[clap(about = "Send an invoke transaction from an account contract")] + Invoke(Invoke), + #[clap(about = "Declare a contract class")] + Declare(Declare), + #[clap(about = "Deploy contract via the Universal Deployer Contract")] + Deploy(Deploy), + // + // Misc + // + #[clap(about = "Generate shell completions script")] + Completions(Completions), + // + // Experimental + // + #[clap( + about = "Experimental commands for fun and profit", + long_about = "Experimental new commands that are shipped with no stability guarantee. \ + They might break or be removed anytime." + )] + Lab(Lab), +} + +pub async fn run_command(cli: Cli) -> Result<()> { + match (cli.version, cli.command) { + (false, None) => Ok(Cli::command().print_help()?), + (true, _) => { + println!( + "{}", + if cli.verbose { + VERSION_STRING_VERBOSE + } else { + VERSION_STRING + } + ); + + Ok(()) + } + (false, Some(command)) => match command { + Subcommands::Selector(cmd) => cmd.run(), + Subcommands::ClassHash(cmd) => cmd.run(), + Subcommands::Abi(cmd) => cmd.run(), + Subcommands::ToCairoString(cmd) => cmd.run(), + Subcommands::ParseCairoString(cmd) => cmd.run(), + Subcommands::Mont(cmd) => cmd.run(), + Subcommands::Call(cmd) => cmd.run().await, + Subcommands::Transaction(cmd) => cmd.run().await, + Subcommands::BlockNumber(cmd) => cmd.run().await, + Subcommands::BlockHash(cmd) => cmd.run().await, + Subcommands::Block(cmd) => cmd.run().await, + Subcommands::BlockTime(cmd) => cmd.run().await, + Subcommands::StateUpdate(cmd) => cmd.run().await, + Subcommands::BlockTraces(cmd) => cmd.run().await, + Subcommands::Status(cmd) => cmd.run().await, + Subcommands::Receipt(cmd) => cmd.run().await, + Subcommands::Trace(cmd) => cmd.run().await, + Subcommands::ChainId(cmd) => cmd.run().await, + Subcommands::Balance(cmd) => cmd.run().await, + Subcommands::Nonce(cmd) => cmd.run().await, + Subcommands::Storage(cmd) => cmd.run().await, + Subcommands::ClassHashAt(cmd) => cmd.run().await, + Subcommands::ClassByHash(cmd) => cmd.run().await, + Subcommands::ClassAt(cmd) => cmd.run().await, + Subcommands::Syncing(cmd) => cmd.run().await, + Subcommands::SpecVersion(cmd) => cmd.run().await, + Subcommands::Signer(cmd) => cmd.run().await, + Subcommands::Ledger(cmd) => cmd.run().await, + Subcommands::Eip2645(cmd) => cmd.run(), + Subcommands::Account(cmd) => cmd.run().await, + Subcommands::Invoke(cmd) => cmd.run().await, + Subcommands::Declare(cmd) => cmd.run().await, + Subcommands::Deploy(cmd) => cmd.run().await, + Subcommands::Completions(cmd) => cmd.run(), + Subcommands::Lab(cmd) => cmd.run(), + }, + } +} + pub async fn watch_tx

(provider: P, transaction_hash: Felt, poll_interval: Duration) -> Result<()> where P: Provider, diff --git a/src/verbosity.rs b/src/verbosity.rs index af6a54a..2c5b402 100644 --- a/src/verbosity.rs +++ b/src/verbosity.rs @@ -6,16 +6,19 @@ use log::LevelFilter; pub struct VerbosityArgs { #[clap(long, help = "Log raw request/response traffic of providers")] log_traffic: bool, + #[clap(long, help = "Use if a logger is already initialized")] + persist_logger: bool, } impl VerbosityArgs { pub fn setup_logging(&self) { - let mut builder = Builder::new(); + if !self.persist_logger { + let mut builder = Builder::new(); + if self.log_traffic { + builder.filter_module("starknet_providers", LevelFilter::Trace); + } - if self.log_traffic { - builder.filter_module("starknet_providers", LevelFilter::Trace); + builder.init(); } - - builder.init(); } }