From 3e569370cf5725e2795d7a270774aa69e79cb1cc Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 20:37:17 +0300 Subject: [PATCH 01/12] Improve CLI UX: add detailed help, about, and usage examples for `forge create` --- crates/forge/src/cmd/create.rs | 49 ++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index 6768b43829836..19741234cde61 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -37,51 +37,66 @@ use std::{borrow::Borrow, marker::PhantomData, path::PathBuf, sync::Arc, time::D merge_impl_figment_convert!(CreateArgs, build, eth); -/// CLI arguments for `forge create`. +/// Deploy a smart contract to the specified network. +/// +/// This command compiles the contract, encodes constructor arguments, and sends a deployment transaction. +/// +/// Example: +/// +/// forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url --private-key --broadcast #[derive(Clone, Debug, Parser)] +#[command( + about = "Deploy a smart contract to the specified network.", + long_about = "Deploy a smart contract to the specified network.\n\ +Compiles the contract, encodes constructor arguments, and sends a deployment transaction.\n\ +EXAMPLES:\n\ + forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url --private-key --broadcast\n\ +Use --verify to automatically verify the contract after deployment.\n\ +See more: https://book.getfoundry.sh/reference/forge/forge-create.html" +)] pub struct CreateArgs { - /// The contract identifier in the form `:`. + /// Contract identifier in the form `:`, e.g. `src/Counter.sol:Counter`. + #[arg(help = "Contract identifier in the form :.", value_name = "CONTRACT")] contract: ContractInfo, - /// The constructor arguments. + /// Constructor arguments as a space-separated list, e.g. `42 "hello"`. #[arg( long, num_args(1..), conflicts_with = "constructor_args_path", value_name = "ARGS", allow_hyphen_values = true, + help = "Constructor arguments as a space-separated list." )] constructor_args: Vec, - /// The path to a file containing the constructor arguments. + /// Path to a file containing constructor arguments (one per line or as JSON array). #[arg( long, value_hint = ValueHint::FilePath, value_name = "PATH", + help = "Path to a file containing constructor arguments (one per line or as JSON array)." )] constructor_args_path: Option, - /// Broadcast the transaction. - #[arg(long)] + /// Broadcast the transaction to the network (otherwise, dry-run only). + #[arg(long, help = "Actually send the deployment transaction to the network.")] pub broadcast: bool, - /// Verify contract after creation. - #[arg(long)] + /// Verify contract after creation (using the selected block explorer). + #[arg(long, help = "Automatically verify the contract after deployment.")] verify: bool, - /// Send via `eth_sendTransaction` using the `--from` argument or `$ETH_FROM` as sender - #[arg(long, requires = "from")] + /// Use `eth_sendTransaction` with an unlocked account (requires --from or $ETH_FROM). + #[arg(long, requires = "from", help = "Send via eth_sendTransaction using an unlocked account.")] unlocked: bool, - /// Prints the standard json compiler input if `--verify` is provided. - /// - /// The standard json compiler input can be used to manually submit contract verification in - /// the browser. - #[arg(long, requires = "verify")] + /// Print the standard JSON compiler input (for manual verification in a browser). + #[arg(long, requires = "verify", help = "Print the standard JSON compiler input if --verify is provided.")] show_standard_json_input: bool, - /// Timeout to use for broadcasting transactions. - #[arg(long, env = "ETH_TIMEOUT")] + /// Timeout (in seconds) for broadcasting transactions. + #[arg(long, env = "ETH_TIMEOUT", value_name = "SECONDS", help = "Timeout in seconds for broadcasting transactions.")] pub timeout: Option, #[command(flatten)] From e079aa3ab19ee6fc13ae8cde5224d7b56b493672 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 20:38:13 +0300 Subject: [PATCH 02/12] Improve `cast call` CLI: detailed help, about, and usage examples for all args --- crates/cast/src/cmd/call.rs | 127 ++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index 315410b8db3cb..339ba088ca21d 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -42,76 +42,69 @@ use super::run::fetch_contracts_bytecode_from_trace; static OVERRIDE_PATTERN: LazyLock = LazyLock::new(|| Regex::new(r"^([^:]+):([^:]+):([^:]+)$").unwrap()); -/// CLI arguments for `cast call`. +/// Call a contract function locally (eth_call) and print the result. /// -/// ## State Override Flags +/// Example: /// -/// The following flags can be used to override the state for the call: -/// -/// * `--override-balance
:` - Override the balance of an account -/// * `--override-nonce
:` - Override the nonce of an account -/// * `--override-code
:` - Override the code of an account -/// * `--override-state
::` - Override a storage slot of an account -/// -/// Multiple overrides can be specified for the same account. For example: -/// -/// ```bash -/// cast call 0x... "transfer(address,uint256)" 0x... 100 \ -/// --override-balance 0x123:0x1234 \ -/// --override-nonce 0x123:1 \ -/// --override-code 0x123:0x1234 \ -/// --override-state 0x123:0x1:0x1234 -/// --override-state-diff 0x123:0x1:0x1234 -/// ``` +/// cast call 0xAbC... "balanceOf(address)" 0x123... --rpc-url #[derive(Debug, Parser)] +#[command( + about = "Call a contract function locally (eth_call) and print the result.", + long_about = "Call a contract function locally (eth_call) and print the result.\n\ +EXAMPLES:\n\ + cast call 0xAbC... 'balanceOf(address)' 0x123... --rpc-url \n\ + cast call 0xAbC... --data 0xabcdef... --rpc-url \n\ + cast call 0xAbC... 'transfer(address,uint256)' 0x123... 100 --override-balance 0x123:1000\n\ +See more: https://book.getfoundry.sh/reference/cast/cast-call.html" +)] pub struct CallArgs { - /// The destination of the transaction. - #[arg(value_parser = NameOrAddress::from_str)] + /// Destination address of the contract to call. + #[arg(help = "Destination address of the contract to call.", value_name = "TO", value_parser = NameOrAddress::from_str)] to: Option, - /// The signature of the function to call. + /// Function signature to call, e.g. `balanceOf(address)`. + #[arg(help = "Function signature to call.", value_name = "SIG")] sig: Option, - /// The arguments of the function to call. + /// Arguments for the function call. + #[arg(help = "Arguments for the function call.", value_name = "ARGS")] args: Vec, - /// Raw hex-encoded data for the transaction. Used instead of \[SIG\] and \[ARGS\]. + /// Raw hex-encoded data for the transaction. Used instead of [SIG] and [ARGS]. #[arg( long, - conflicts_with_all = &["sig", "args"] + conflicts_with_all = &["sig", "args"], + value_name = "DATA", + help = "Raw hex-encoded data for the transaction. Used instead of [SIG] and [ARGS]." )] data: Option, - /// Forks the remote rpc, executes the transaction locally and prints a trace - #[arg(long, default_value_t = false)] + /// Forks the remote rpc, executes the transaction locally and prints a trace. + #[arg(long, default_value_t = false, help = "Forks the remote rpc, executes the transaction locally and prints a trace.")] trace: bool, - /// Opens an interactive debugger. - /// Can only be used with `--trace`. - #[arg(long, requires = "trace")] + /// Opens an interactive debugger (requires --trace). + #[arg(long, requires = "trace", help = "Opens an interactive debugger (requires --trace).")] debug: bool, - #[arg(long, requires = "trace")] + /// Decode internal calls in traces (requires --trace). + #[arg(long, requires = "trace", help = "Decode internal calls in traces (requires --trace).")] decode_internal: bool, - /// Labels to apply to the traces; format: `address:label`. - /// Can only be used with `--trace`. - #[arg(long, requires = "trace")] + /// Labels to apply to the traces; format: `address:label` (requires --trace). + #[arg(long, requires = "trace", help = "Labels to apply to the traces; format: address:label (requires --trace).")] labels: Vec, - /// The EVM Version to use. - /// Can only be used with `--trace`. - #[arg(long, requires = "trace")] + /// EVM Version to use (requires --trace). + #[arg(long, requires = "trace", value_name = "EVM_VERSION", help = "EVM Version to use (requires --trace).")] evm_version: Option, - /// The block height to query at. - /// - /// Can also be the tags earliest, finalized, safe, latest, or pending. - #[arg(long, short)] + /// Block height to query at (number or tag: earliest, latest, pending, etc). + #[arg(long, short, value_name = "BLOCK", help = "Block height to query at (number or tag: earliest, latest, pending, etc).")] block: Option, /// Enable Odyssey features. - #[arg(long, alias = "alphanet")] + #[arg(long, alias = "alphanet", help = "Enable Odyssey features.")] pub odyssey: bool, #[command(subcommand)] @@ -124,63 +117,57 @@ pub struct CallArgs { eth: EthereumOpts, /// Use current project artifacts for trace decoding. - #[arg(long, visible_alias = "la")] + #[arg(long, visible_alias = "la", help = "Use current project artifacts for trace decoding.")] pub with_local_artifacts: bool, - /// Override the balance of an account. - /// Format: address:balance - #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE")] + /// Override the balance of an account. Format: address:balance + #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE", help = "Override the balance of an account. Format: address:balance")] pub balance_overrides: Option>, - /// Override the nonce of an account. - /// Format: address:nonce - #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE")] + /// Override the nonce of an account. Format: address:nonce + #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE", help = "Override the nonce of an account. Format: address:nonce")] pub nonce_overrides: Option>, - /// Override the code of an account. - /// Format: address:code - #[arg(long = "override-code", value_name = "ADDRESS:CODE")] + /// Override the code of an account. Format: address:code + #[arg(long = "override-code", value_name = "ADDRESS:CODE", help = "Override the code of an account. Format: address:code")] pub code_overrides: Option>, - /// Override the state of an account. - /// Format: address:slot:value - #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE")] + /// Override the state of an account. Format: address:slot:value + #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE", help = "Override the state of an account. Format: address:slot:value")] pub state_overrides: Option>, - /// Override the state diff of an account. - /// Format: address:slot:value - #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE")] + /// Override the state diff of an account. Format: address:slot:value + #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE", help = "Override the state diff of an account. Format: address:slot:value")] pub state_diff_overrides: Option>, /// Override the block timestamp. - #[arg(long = "block.time", value_name = "TIME")] + #[arg(long = "block.time", value_name = "TIME", help = "Override the block timestamp.")] pub block_time: Option, /// Override the block number. - #[arg(long = "block.number", value_name = "NUMBER")] + #[arg(long = "block.number", value_name = "NUMBER", help = "Override the block number.")] pub block_number: Option, } #[derive(Debug, Parser)] pub enum CallSubcommands { - /// ignores the address field and simulates creating a contract + /// Simulate contract creation (ignores the address field). #[command(name = "--create")] Create { - /// Bytecode of contract. + /// Bytecode of contract to deploy. + #[arg(help = "Bytecode of contract to deploy.", value_name = "BYTECODE")] code: String, - /// The signature of the constructor. + /// Constructor signature, e.g. `constructor(uint256)`. + #[arg(help = "Constructor signature.", value_name = "SIG")] sig: Option, - /// The arguments of the constructor. + /// Arguments for the constructor. + #[arg(help = "Arguments for the constructor.", value_name = "ARGS")] args: Vec, - /// Ether to send in the transaction. - /// - /// Either specified in wei, or as a string with a unit type. - /// - /// Examples: 1ether, 10gwei, 0.01ether - #[arg(long, value_parser = parse_ether_value)] + /// Ether to send in the transaction (e.g. 1ether, 10gwei, 0.01ether). + #[arg(long, value_parser = parse_ether_value, value_name = "VALUE", help = "Ether to send in the transaction (e.g. 1ether, 10gwei, 0.01ether).")] value: Option, }, } From b0e4202c9c1296b49caeb4f26fd2d6fc88c35d2f Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 20:38:54 +0300 Subject: [PATCH 03/12] Refine `cast send` CLI: add comprehensive help, about, and usage examples --- crates/cast/src/cmd/send.rs | 57 ++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 35ec92f737e0e..846ab0697e93a 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -17,38 +17,53 @@ use foundry_cli::{ }; use std::{path::PathBuf, str::FromStr}; -/// CLI arguments for `cast send`. +/// Send a transaction to a contract or deploy a new contract. +/// +/// Example: +/// +/// cast send 0xAbC... "transfer(address,uint256)" 0x123... 100 --private-key --rpc-url +/// cast send --create --private-key --rpc-url #[derive(Debug, Parser)] +#[command( + about = "Send a transaction to a contract or deploy a new contract.", + long_about = "Send a transaction to a contract or deploy a new contract.\n\ +EXAMPLES:\n\ + cast send 0xAbC... 'transfer(address,uint256)' 0x123... 100 --private-key --rpc-url \n\ + cast send --create --private-key --rpc-url \n\ +See more: https://book.getfoundry.sh/reference/cast/cast-send.html" +)] pub struct SendTxArgs { - /// The destination of the transaction. + /// Destination address of the transaction (contract or EOA). /// - /// If not provided, you must use cast send --create. - #[arg(value_parser = NameOrAddress::from_str)] + /// If not provided, you must use `cast send --create`. + #[arg(help = "Destination address of the transaction.", value_name = "TO", value_parser = NameOrAddress::from_str)] to: Option, - /// The signature of the function to call. + /// Function signature to call, e.g. `transfer(address,uint256)`. + #[arg(help = "Function signature to call.", value_name = "SIG")] sig: Option, - /// The arguments of the function to call. + /// Arguments for the function call. + #[arg(help = "Arguments for the function call.", value_name = "ARGS")] args: Vec, /// Only print the transaction hash and exit immediately. - #[arg(id = "async", long = "async", alias = "cast-async", env = "CAST_ASYNC")] + #[arg(id = "async", long = "async", alias = "cast-async", env = "CAST_ASYNC", help = "Only print the transaction hash and exit immediately.")] cast_async: bool, - /// The number of confirmations until the receipt is fetched. - #[arg(long, default_value = "1")] + /// Number of confirmations to wait for the receipt. + #[arg(long, default_value = "1", value_name = "NUM", help = "Number of confirmations to wait for the receipt.")] confirmations: u64, #[command(subcommand)] command: Option, - /// Send via `eth_sendTransaction` using the `--from` argument or $ETH_FROM as sender - #[arg(long, requires = "from")] + /// Use `eth_sendTransaction` with an unlocked account (requires --from or $ETH_FROM). + #[arg(long, requires = "from", help = "Send via eth_sendTransaction using an unlocked account.")] unlocked: bool, - /// Timeout for sending the transaction. - #[arg(long, env = "ETH_TIMEOUT")] + /// Timeout (in seconds) for sending the transaction. + #[arg(long, env = "ETH_TIMEOUT", value_name = "SECONDS", help = "Timeout in seconds for sending the transaction.")] pub timeout: Option, #[command(flatten)] @@ -57,29 +72,33 @@ pub struct SendTxArgs { #[command(flatten)] eth: EthereumOpts, - /// The path of blob data to be sent. + /// Path to a file containing blob data to be sent. #[arg( long, value_name = "BLOB_DATA_PATH", conflicts_with = "legacy", requires = "blob", - help_heading = "Transaction options" + help_heading = "Transaction options", + help = "Path to a file containing blob data to be sent." )] path: Option, } #[derive(Debug, Parser)] pub enum SendTxSubcommands { - /// Use to deploy raw contract bytecode. + /// Deploy raw contract bytecode as a new contract. #[command(name = "--create")] Create { - /// The bytecode of the contract to deploy. + /// Bytecode of the contract to deploy. + #[arg(help = "Bytecode of the contract to deploy.", value_name = "BYTECODE")] code: String, - /// The signature of the function to call. + /// Constructor signature, e.g. `constructor(uint256)`. + #[arg(help = "Constructor signature.", value_name = "SIG")] sig: Option, - /// The arguments of the function to call. + /// Arguments for the constructor. + #[arg(help = "Arguments for the constructor.", value_name = "ARGS")] args: Vec, }, } From 57735f47f2349da56e36f343eaee82b90a79d2d0 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 20:39:42 +0300 Subject: [PATCH 04/12] Enhance `forge verify-contract` CLI: better help, about, and real usage examples --- crates/verify/src/verify.rs | 79 ++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/crates/verify/src/verify.rs b/crates/verify/src/verify.rs index 804813c7a96e7..d5df0c678d2a1 100644 --- a/crates/verify/src/verify.rs +++ b/crates/verify/src/verify.rs @@ -54,86 +54,93 @@ impl Default for VerifierArgs { } } -/// CLI arguments for `forge verify-contract`. +/// Submit a contract's source code for verification on a block explorer (e.g. Etherscan, Sourcify). +/// +/// Example: +/// +/// forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key #[derive(Clone, Debug, Parser)] +#[command( + about = "Verify a deployed contract's source code on a block explorer.", + long_about = "Submit a contract's source code for verification on a block explorer (e.g. Etherscan, Sourcify).\n\ +EXAMPLES:\n\ + forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key \n\ + forge verify-contract 0x123... src/Counter.sol:Counter --constructor-args 42 --compiler-version 0.8.20\n\ +See more: https://book.getfoundry.sh/reference/forge/forge-verify-contract.html" +)] pub struct VerifyArgs { - /// The address of the contract to verify. + /// Address of the deployed contract to verify. + #[arg(help = "Address of the deployed contract to verify.", value_name = "ADDRESS")] pub address: Address, - /// The contract identifier in the form `:`. + /// Contract identifier in the form `:`, e.g. `src/Counter.sol:Counter`. + #[arg(help = "Contract identifier in the form :.", value_name = "CONTRACT")] pub contract: Option, - /// The ABI-encoded constructor arguments. + /// ABI-encoded constructor arguments (hex string, e.g. 000000...) #[arg( long, conflicts_with = "constructor_args_path", value_name = "ARGS", - visible_alias = "encoded-constructor-args" + visible_alias = "encoded-constructor-args", + help = "ABI-encoded constructor arguments as a hex string." )] pub constructor_args: Option, - /// The path to a file containing the constructor arguments. - #[arg(long, value_hint = ValueHint::FilePath, value_name = "PATH")] + /// Path to a file containing constructor arguments (one per line or as JSON array). + #[arg(long, value_hint = ValueHint::FilePath, value_name = "PATH", help = "Path to a file containing constructor arguments.")] pub constructor_args_path: Option, /// Try to extract constructor arguments from on-chain creation code. - #[arg(long)] + #[arg(long, help = "Try to extract constructor arguments from on-chain creation code.")] pub guess_constructor_args: bool, - /// The `solc` version to use to build the smart contract. - #[arg(long, value_name = "VERSION")] + /// Solidity compiler version to use (e.g. 0.8.20). + #[arg(long, value_name = "VERSION", help = "Solidity compiler version to use for verification.")] pub compiler_version: Option, - /// The compilation profile to use to build the smart contract. - #[arg(long, value_name = "PROFILE_NAME")] + /// Compilation profile to use (e.g. default, release). + #[arg(long, value_name = "PROFILE_NAME", help = "Compilation profile to use for building the contract.")] pub compilation_profile: Option, - /// The number of optimization runs used to build the smart contract. - #[arg(long, visible_alias = "optimizer-runs", value_name = "NUM")] + /// Number of optimizer runs used to build the contract. + #[arg(long, visible_alias = "optimizer-runs", value_name = "NUM", help = "Number of optimizer runs used during compilation.")] pub num_of_optimizations: Option, /// Flatten the source code before verifying. - #[arg(long)] + #[arg(long, help = "Flatten the source code before verifying.")] pub flatten: bool, - /// Do not compile the flattened smart contract before verifying (if --flatten is passed). - #[arg(short, long)] + /// Do not compile the flattened contract before verifying (if --flatten is passed). + #[arg(short, long, help = "Do not compile the flattened contract before verifying (if --flatten is passed).")] pub force: bool, /// Do not check if the contract is already verified before verifying. - #[arg(long)] + #[arg(long, help = "Skip the check if the contract is already verified before submitting.")] pub skip_is_verified_check: bool, /// Wait for verification result after submission. - #[arg(long)] + #[arg(long, help = "Wait for verification result after submission.")] pub watch: bool, - /// Set pre-linked libraries. - #[arg(long, help_heading = "Linker options", env = "DAPP_LIBRARIES")] + /// Pre-linked libraries in the format :=
(repeatable). + #[arg(long, help_heading = "Linker options", env = "DAPP_LIBRARIES", value_name = "LIBRARIES", help = "Pre-linked libraries in the format :=
.")] pub libraries: Vec, - /// The project's root path. - /// - /// By default root of the Git repository, if in one, - /// or the current working directory. - #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH")] + /// Project's root path (default: git root or current directory). + #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH", help = "Project's root path.")] pub root: Option, - /// Prints the standard json compiler input. - /// - /// The standard json compiler input can be used to manually submit contract verification in - /// the browser. - #[arg(long, conflicts_with = "flatten")] + /// Print the standard JSON compiler input (for manual verification in a browser). + #[arg(long, conflicts_with = "flatten", help = "Print the standard JSON compiler input for manual verification.")] pub show_standard_json_input: bool, /// Use the Yul intermediate representation compilation pipeline. - #[arg(long)] + #[arg(long, help = "Use the Yul intermediate representation compilation pipeline.")] pub via_ir: bool, - /// The EVM version to use. - /// - /// Overrides the version specified in the config. - #[arg(long)] + /// EVM version to use (overrides config). + #[arg(long, value_name = "EVM_VERSION", help = "EVM version to use for verification.")] pub evm_version: Option, #[command(flatten)] From c91dc10c02f148b126375dd49a01ffc5b90eef82 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:02:40 +0300 Subject: [PATCH 05/12] Update call.rs --- crates/cast/src/cmd/call.rs | 47 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index 339ba088ca21d..ba48b121c4e28 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -59,52 +59,51 @@ See more: https://book.getfoundry.sh/reference/cast/cast-call.html" )] pub struct CallArgs { /// Destination address of the contract to call. - #[arg(help = "Destination address of the contract to call.", value_name = "TO", value_parser = NameOrAddress::from_str)] + #[arg(value_name = "TO", value_parser = NameOrAddress::from_str)] to: Option, /// Function signature to call, e.g. `balanceOf(address)`. - #[arg(help = "Function signature to call.", value_name = "SIG")] + #[arg(value_name = "SIG")] sig: Option, /// Arguments for the function call. - #[arg(help = "Arguments for the function call.", value_name = "ARGS")] + #[arg(value_name = "ARGS")] args: Vec, - /// Raw hex-encoded data for the transaction. Used instead of [SIG] and [ARGS]. + /// Raw hex-encoded data for the transaction. Used instead of \[SIG\] and \[ARGS\]. #[arg( long, conflicts_with_all = &["sig", "args"], value_name = "DATA", - help = "Raw hex-encoded data for the transaction. Used instead of [SIG] and [ARGS]." )] data: Option, /// Forks the remote rpc, executes the transaction locally and prints a trace. - #[arg(long, default_value_t = false, help = "Forks the remote rpc, executes the transaction locally and prints a trace.")] + #[arg(long, default_value_t = false)] trace: bool, /// Opens an interactive debugger (requires --trace). - #[arg(long, requires = "trace", help = "Opens an interactive debugger (requires --trace).")] + #[arg(long, requires = "trace")] debug: bool, /// Decode internal calls in traces (requires --trace). - #[arg(long, requires = "trace", help = "Decode internal calls in traces (requires --trace).")] + #[arg(long, requires = "trace")] decode_internal: bool, /// Labels to apply to the traces; format: `address:label` (requires --trace). - #[arg(long, requires = "trace", help = "Labels to apply to the traces; format: address:label (requires --trace).")] + #[arg(long, requires = "trace")] labels: Vec, /// EVM Version to use (requires --trace). - #[arg(long, requires = "trace", value_name = "EVM_VERSION", help = "EVM Version to use (requires --trace).")] + #[arg(long, requires = "trace", value_name = "EVM_VERSION")] evm_version: Option, /// Block height to query at (number or tag: earliest, latest, pending, etc). - #[arg(long, short, value_name = "BLOCK", help = "Block height to query at (number or tag: earliest, latest, pending, etc).")] + #[arg(long, short, value_name = "BLOCK")] block: Option, /// Enable Odyssey features. - #[arg(long, alias = "alphanet", help = "Enable Odyssey features.")] + #[arg(long, alias = "alphanet")] pub odyssey: bool, #[command(subcommand)] @@ -117,35 +116,35 @@ pub struct CallArgs { eth: EthereumOpts, /// Use current project artifacts for trace decoding. - #[arg(long, visible_alias = "la", help = "Use current project artifacts for trace decoding.")] + #[arg(long, visible_alias = "la")] pub with_local_artifacts: bool, /// Override the balance of an account. Format: address:balance - #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE", help = "Override the balance of an account. Format: address:balance")] + #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE")] pub balance_overrides: Option>, /// Override the nonce of an account. Format: address:nonce - #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE", help = "Override the nonce of an account. Format: address:nonce")] + #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE")] pub nonce_overrides: Option>, /// Override the code of an account. Format: address:code - #[arg(long = "override-code", value_name = "ADDRESS:CODE", help = "Override the code of an account. Format: address:code")] + #[arg(long = "override-code", value_name = "ADDRESS:CODE")] pub code_overrides: Option>, /// Override the state of an account. Format: address:slot:value - #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE", help = "Override the state of an account. Format: address:slot:value")] + #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE")] pub state_overrides: Option>, /// Override the state diff of an account. Format: address:slot:value - #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE", help = "Override the state diff of an account. Format: address:slot:value")] + #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE")] pub state_diff_overrides: Option>, /// Override the block timestamp. - #[arg(long = "block.time", value_name = "TIME", help = "Override the block timestamp.")] + #[arg(long = "block.time", value_name = "TIME")] pub block_time: Option, /// Override the block number. - #[arg(long = "block.number", value_name = "NUMBER", help = "Override the block number.")] + #[arg(long = "block.number", value_name = "NUMBER")] pub block_number: Option, } @@ -155,19 +154,19 @@ pub enum CallSubcommands { #[command(name = "--create")] Create { /// Bytecode of contract to deploy. - #[arg(help = "Bytecode of contract to deploy.", value_name = "BYTECODE")] + #[arg(value_name = "BYTECODE")] code: String, /// Constructor signature, e.g. `constructor(uint256)`. - #[arg(help = "Constructor signature.", value_name = "SIG")] + #[arg(value_name = "SIG")] sig: Option, /// Arguments for the constructor. - #[arg(help = "Arguments for the constructor.", value_name = "ARGS")] + #[arg(value_name = "ARGS")] args: Vec, /// Ether to send in the transaction (e.g. 1ether, 10gwei, 0.01ether). - #[arg(long, value_parser = parse_ether_value, value_name = "VALUE", help = "Ether to send in the transaction (e.g. 1ether, 10gwei, 0.01ether).")] + #[arg(long, value_parser = parse_ether_value, value_name = "VALUE")] value: Option, }, } From 27dfdabfd4dae01143afd7b5660f5697bb448b58 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:02:58 +0300 Subject: [PATCH 06/12] Update send.rs --- crates/cast/src/cmd/send.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 846ab0697e93a..7924747350b78 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -21,49 +21,49 @@ use std::{path::PathBuf, str::FromStr}; /// /// Example: /// -/// cast send 0xAbC... "transfer(address,uint256)" 0x123... 100 --private-key --rpc-url -/// cast send --create --private-key --rpc-url +/// cast send 0xAbC... "transfer(address,uint256)" 0x123... 100 --private-key <KEY> --rpc-url <URL> +/// cast send --create <BYTECODE> --private-key <KEY> --rpc-url <URL> #[derive(Debug, Parser)] #[command( about = "Send a transaction to a contract or deploy a new contract.", long_about = "Send a transaction to a contract or deploy a new contract.\n\ EXAMPLES:\n\ - cast send 0xAbC... 'transfer(address,uint256)' 0x123... 100 --private-key --rpc-url \n\ - cast send --create --private-key --rpc-url \n\ + cast send 0xAbC... 'transfer(address,uint256)' 0x123... 100 --private-key <KEY> --rpc-url <URL>\n\ + cast send --create <BYTECODE> --private-key <KEY> --rpc-url <URL>\n\ See more: https://book.getfoundry.sh/reference/cast/cast-send.html" )] pub struct SendTxArgs { /// Destination address of the transaction (contract or EOA). /// /// If not provided, you must use `cast send --create`. - #[arg(help = "Destination address of the transaction.", value_name = "TO", value_parser = NameOrAddress::from_str)] + #[arg(value_name = "TO", value_parser = NameOrAddress::from_str)] to: Option, /// Function signature to call, e.g. `transfer(address,uint256)`. - #[arg(help = "Function signature to call.", value_name = "SIG")] + #[arg(value_name = "SIG")] sig: Option, /// Arguments for the function call. - #[arg(help = "Arguments for the function call.", value_name = "ARGS")] + #[arg(value_name = "ARGS")] args: Vec, /// Only print the transaction hash and exit immediately. - #[arg(id = "async", long = "async", alias = "cast-async", env = "CAST_ASYNC", help = "Only print the transaction hash and exit immediately.")] + #[arg(id = "async", long = "async", alias = "cast-async", env = "CAST_ASYNC")] cast_async: bool, /// Number of confirmations to wait for the receipt. - #[arg(long, default_value = "1", value_name = "NUM", help = "Number of confirmations to wait for the receipt.")] + #[arg(long, default_value = "1", value_name = "NUM")] confirmations: u64, #[command(subcommand)] command: Option, /// Use `eth_sendTransaction` with an unlocked account (requires --from or $ETH_FROM). - #[arg(long, requires = "from", help = "Send via eth_sendTransaction using an unlocked account.")] + #[arg(long, requires = "from")] unlocked: bool, /// Timeout (in seconds) for sending the transaction. - #[arg(long, env = "ETH_TIMEOUT", value_name = "SECONDS", help = "Timeout in seconds for sending the transaction.")] + #[arg(long, env = "ETH_TIMEOUT", value_name = "SECONDS")] pub timeout: Option, #[command(flatten)] @@ -78,8 +78,7 @@ pub struct SendTxArgs { value_name = "BLOB_DATA_PATH", conflicts_with = "legacy", requires = "blob", - help_heading = "Transaction options", - help = "Path to a file containing blob data to be sent." + help_heading = "Transaction options" )] path: Option, } @@ -90,15 +89,15 @@ pub enum SendTxSubcommands { #[command(name = "--create")] Create { /// Bytecode of the contract to deploy. - #[arg(help = "Bytecode of the contract to deploy.", value_name = "BYTECODE")] + #[arg(value_name = "BYTECODE")] code: String, /// Constructor signature, e.g. `constructor(uint256)`. - #[arg(help = "Constructor signature.", value_name = "SIG")] + #[arg(value_name = "SIG")] sig: Option, /// Arguments for the constructor. - #[arg(help = "Arguments for the constructor.", value_name = "ARGS")] + #[arg(value_name = "ARGS")] args: Vec, }, } From 876ce91cf3604c2ee889796107467868df10924b Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:03:16 +0300 Subject: [PATCH 07/12] Update create.rs --- crates/forge/src/cmd/create.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index 19741234cde61..525eff864794e 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -43,30 +43,29 @@ merge_impl_figment_convert!(CreateArgs, build, eth); /// /// Example: /// -/// forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url --private-key --broadcast +/// forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url <URL> --private-key <KEY> --broadcast #[derive(Clone, Debug, Parser)] #[command( about = "Deploy a smart contract to the specified network.", long_about = "Deploy a smart contract to the specified network.\n\ Compiles the contract, encodes constructor arguments, and sends a deployment transaction.\n\ EXAMPLES:\n\ - forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url --private-key --broadcast\n\ + forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url <URL> --private-key <KEY> --broadcast\n\ Use --verify to automatically verify the contract after deployment.\n\ See more: https://book.getfoundry.sh/reference/forge/forge-create.html" )] pub struct CreateArgs { /// Contract identifier in the form `:`, e.g. `src/Counter.sol:Counter`. - #[arg(help = "Contract identifier in the form :.", value_name = "CONTRACT")] + #[arg(value_name = "CONTRACT")] contract: ContractInfo, - /// Constructor arguments as a space-separated list, e.g. `42 "hello"`. + /// Constructor arguments as a space-separated list, e.g. `42 \"hello\"`. #[arg( long, num_args(1..), conflicts_with = "constructor_args_path", value_name = "ARGS", allow_hyphen_values = true, - help = "Constructor arguments as a space-separated list." )] constructor_args: Vec, @@ -75,28 +74,27 @@ pub struct CreateArgs { long, value_hint = ValueHint::FilePath, value_name = "PATH", - help = "Path to a file containing constructor arguments (one per line or as JSON array)." )] constructor_args_path: Option, /// Broadcast the transaction to the network (otherwise, dry-run only). - #[arg(long, help = "Actually send the deployment transaction to the network.")] + #[arg(long)] pub broadcast: bool, /// Verify contract after creation (using the selected block explorer). - #[arg(long, help = "Automatically verify the contract after deployment.")] + #[arg(long)] verify: bool, /// Use `eth_sendTransaction` with an unlocked account (requires --from or $ETH_FROM). - #[arg(long, requires = "from", help = "Send via eth_sendTransaction using an unlocked account.")] + #[arg(long, requires = "from")] unlocked: bool, /// Print the standard JSON compiler input (for manual verification in a browser). - #[arg(long, requires = "verify", help = "Print the standard JSON compiler input if --verify is provided.")] + #[arg(long, requires = "verify")] show_standard_json_input: bool, /// Timeout (in seconds) for broadcasting transactions. - #[arg(long, env = "ETH_TIMEOUT", value_name = "SECONDS", help = "Timeout in seconds for broadcasting transactions.")] + #[arg(long, env = "ETH_TIMEOUT", value_name = "SECONDS")] pub timeout: Option, #[command(flatten)] From 57c03df406550e318a58288ff8d336c95ae5d5b9 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:03:31 +0300 Subject: [PATCH 08/12] Update verify.rs --- crates/verify/src/verify.rs | 41 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/crates/verify/src/verify.rs b/crates/verify/src/verify.rs index d5df0c678d2a1..0882cb6855560 100644 --- a/crates/verify/src/verify.rs +++ b/crates/verify/src/verify.rs @@ -58,23 +58,23 @@ impl Default for VerifierArgs { /// /// Example: /// -/// forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key +/// forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key <KEY> #[derive(Clone, Debug, Parser)] #[command( about = "Verify a deployed contract's source code on a block explorer.", long_about = "Submit a contract's source code for verification on a block explorer (e.g. Etherscan, Sourcify).\n\ EXAMPLES:\n\ - forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key \n\ + forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key <KEY>\n\ forge verify-contract 0x123... src/Counter.sol:Counter --constructor-args 42 --compiler-version 0.8.20\n\ See more: https://book.getfoundry.sh/reference/forge/forge-verify-contract.html" )] pub struct VerifyArgs { /// Address of the deployed contract to verify. - #[arg(help = "Address of the deployed contract to verify.", value_name = "ADDRESS")] + #[arg(value_name = "ADDRESS")] pub address: Address, /// Contract identifier in the form `:`, e.g. `src/Counter.sol:Counter`. - #[arg(help = "Contract identifier in the form :.", value_name = "CONTRACT")] + #[arg(value_name = "CONTRACT")] pub contract: Option, /// ABI-encoded constructor arguments (hex string, e.g. 000000...) @@ -82,65 +82,64 @@ pub struct VerifyArgs { long, conflicts_with = "constructor_args_path", value_name = "ARGS", - visible_alias = "encoded-constructor-args", - help = "ABI-encoded constructor arguments as a hex string." + visible_alias = "encoded-constructor-args" )] pub constructor_args: Option, /// Path to a file containing constructor arguments (one per line or as JSON array). - #[arg(long, value_hint = ValueHint::FilePath, value_name = "PATH", help = "Path to a file containing constructor arguments.")] + #[arg(long, value_hint = ValueHint::FilePath, value_name = "PATH")] pub constructor_args_path: Option, /// Try to extract constructor arguments from on-chain creation code. - #[arg(long, help = "Try to extract constructor arguments from on-chain creation code.")] + #[arg(long)] pub guess_constructor_args: bool, /// Solidity compiler version to use (e.g. 0.8.20). - #[arg(long, value_name = "VERSION", help = "Solidity compiler version to use for verification.")] + #[arg(long, value_name = "VERSION")] pub compiler_version: Option, /// Compilation profile to use (e.g. default, release). - #[arg(long, value_name = "PROFILE_NAME", help = "Compilation profile to use for building the contract.")] + #[arg(long, value_name = "PROFILE_NAME")] pub compilation_profile: Option, /// Number of optimizer runs used to build the contract. - #[arg(long, visible_alias = "optimizer-runs", value_name = "NUM", help = "Number of optimizer runs used during compilation.")] + #[arg(long, visible_alias = "optimizer-runs", value_name = "NUM")] pub num_of_optimizations: Option, /// Flatten the source code before verifying. - #[arg(long, help = "Flatten the source code before verifying.")] + #[arg(long)] pub flatten: bool, /// Do not compile the flattened contract before verifying (if --flatten is passed). - #[arg(short, long, help = "Do not compile the flattened contract before verifying (if --flatten is passed).")] + #[arg(short, long)] pub force: bool, /// Do not check if the contract is already verified before verifying. - #[arg(long, help = "Skip the check if the contract is already verified before submitting.")] + #[arg(long)] pub skip_is_verified_check: bool, /// Wait for verification result after submission. - #[arg(long, help = "Wait for verification result after submission.")] + #[arg(long)] pub watch: bool, /// Pre-linked libraries in the format :=
(repeatable). - #[arg(long, help_heading = "Linker options", env = "DAPP_LIBRARIES", value_name = "LIBRARIES", help = "Pre-linked libraries in the format :=
.")] + #[arg(long, help_heading = "Linker options", env = "DAPP_LIBRARIES", value_name = "LIBRARIES")] pub libraries: Vec, /// Project's root path (default: git root or current directory). - #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH", help = "Project's root path.")] + #[arg(long, value_hint = ValueHint::DirPath, value_name = "PATH")] pub root: Option, /// Print the standard JSON compiler input (for manual verification in a browser). - #[arg(long, conflicts_with = "flatten", help = "Print the standard JSON compiler input for manual verification.")] + #[arg(long, conflicts_with = "flatten")] pub show_standard_json_input: bool, /// Use the Yul intermediate representation compilation pipeline. - #[arg(long, help = "Use the Yul intermediate representation compilation pipeline.")] + #[arg(long)] pub via_ir: bool, /// EVM version to use (overrides config). - #[arg(long, value_name = "EVM_VERSION", help = "EVM version to use for verification.")] + #[arg(long, value_name = "EVM_VERSION")] pub evm_version: Option, #[command(flatten)] @@ -230,7 +229,7 @@ impl VerifyArgs { .create_verify_request(&self, &context) .await?; sh_println!("{}", args.source)?; - return Ok(()) + return Ok(()); } let verifier_url = self.verifier.verifier_url.clone(); From 5d3ba1f0bb3d8af5020099bdb3293502fddfaea4 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:23:27 +0300 Subject: [PATCH 09/12] Update create.rs --- crates/forge/src/cmd/create.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index 525eff864794e..ab5329aba4723 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -39,11 +39,13 @@ merge_impl_figment_convert!(CreateArgs, build, eth); /// Deploy a smart contract to the specified network. /// -/// This command compiles the contract, encodes constructor arguments, and sends a deployment transaction. +/// This command compiles the contract, encodes constructor arguments, and sends a deployment +/// transaction. /// /// Example: /// -/// forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url <URL> --private-key <KEY> --broadcast +/// forge create src/Counter.sol:Counter --constructor-args 42 --rpc-url <URL> --private-key +/// <KEY> --broadcast #[derive(Clone, Debug, Parser)] #[command( about = "Deploy a smart contract to the specified network.", From 83494a6d30c1c04fcb1667ae42eab7f64854e601 Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:23:47 +0300 Subject: [PATCH 10/12] Update call.rs --- crates/cast/src/cmd/call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/cmd/call.rs b/crates/cast/src/cmd/call.rs index ba48b121c4e28..f6f80f7a09af9 100644 --- a/crates/cast/src/cmd/call.rs +++ b/crates/cast/src/cmd/call.rs @@ -46,7 +46,7 @@ static OVERRIDE_PATTERN: LazyLock = /// /// Example: /// -/// cast call 0xAbC... "balanceOf(address)" 0x123... --rpc-url +/// cast call 0xAbC... "balanceOf(address)" 0x123... --rpc-url <URL> #[derive(Debug, Parser)] #[command( about = "Call a contract function locally (eth_call) and print the result.", From 487769c8e684b683b5d90cc63d7a2d8a4e7bccbe Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:24:00 +0300 Subject: [PATCH 11/12] Update send.rs --- crates/cast/src/cmd/send.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 7924747350b78..fce367a4e48c2 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -21,8 +21,8 @@ use std::{path::PathBuf, str::FromStr}; /// /// Example: /// -/// cast send 0xAbC... "transfer(address,uint256)" 0x123... 100 --private-key <KEY> --rpc-url <URL> -/// cast send --create <BYTECODE> --private-key <KEY> --rpc-url <URL> +/// cast send 0xAbC... "transfer(address,uint256)" 0x123... 100 --private-key <KEY> --rpc-url +/// <URL> cast send --create <BYTECODE> --private-key <KEY> --rpc-url <URL> #[derive(Debug, Parser)] #[command( about = "Send a transaction to a contract or deploy a new contract.", From 5aebad3b6ab8dceaa6545319417e73dfc4db7d8c Mon Sep 17 00:00:00 2001 From: MozirDmitriy Date: Thu, 3 Jul 2025 21:24:13 +0300 Subject: [PATCH 12/12] Update verify.rs --- crates/verify/src/verify.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/verify/src/verify.rs b/crates/verify/src/verify.rs index 0882cb6855560..ad417c2075b49 100644 --- a/crates/verify/src/verify.rs +++ b/crates/verify/src/verify.rs @@ -58,7 +58,8 @@ impl Default for VerifierArgs { /// /// Example: /// -/// forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 --etherscan-api-key <KEY> +/// forge verify-contract 0x123... src/Counter.sol:Counter --compiler-version 0.8.20 +/// --etherscan-api-key <KEY> #[derive(Clone, Debug, Parser)] #[command( about = "Verify a deployed contract's source code on a block explorer.", @@ -122,7 +123,7 @@ pub struct VerifyArgs { #[arg(long)] pub watch: bool, - /// Pre-linked libraries in the format :=
(repeatable). + /// Pre-linked libraries in the format <file>:<lib>=<address> (repeatable). #[arg(long, help_heading = "Linker options", env = "DAPP_LIBRARIES", value_name = "LIBRARIES")] pub libraries: Vec,