1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use clap::{Parser, Subcommand};
use anyhow::Result;
mod commands;
mod scaffold;
mod deployer;
mod gas;
mod linter;
mod config;
#[derive(Parser)]
#[command(
name = "fhevm-forge",
about = "Foundry scaffold, deployer, gas estimator and linter for Zama FHEVM",
version = env!("CARGO_PKG_VERSION"),
long_about = None,
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Scaffold a new FHEVM Foundry project
Init {
/// Project name and directory to create
name: String,
/// Starting template
/// Options: blank | erc7984 | lending | auction | voting
#[arg(short, long)]
template: Option<String>,
},
/// Deploy contracts to one or more chains
Deploy {
/// Comma-separated chain keys: sepolia,mainnet,base,arbitrum
#[arg(short, long, default_value = "sepolia")]
chains: String,
/// Contract name (matches Deploy<Name>.s.sol script)
#[arg(short, long)]
contract: String,
/// Simulate without broadcasting transactions
#[arg(long)]
dry_run: bool,
},
/// Generate FHE-aware gas cost report
Gas {
/// Contract to analyze (default: all contracts)
#[arg(short, long)]
contract: Option<String>,
/// Output format: terminal | json | markdown
#[arg(short, long, default_value = "terminal")]
output: String,
},
/// Run FHEVM static analyzer on Solidity source files
Lint {
/// Path to analyze
#[arg(default_value = "./src")]
path: String,
/// Auto-fix safe issues (FHEVM-001, FHEVM-003)
#[arg(long)]
fix: bool,
/// Comma-separated rule IDs to suppress (e.g. FHEVM-001,FHEVM-003)
#[arg(long, value_delimiter = ',')]
ignore: Vec<String>,
/// Print all available rule IDs and exit
#[arg(long)]
list_rules: bool,
},
/// Check FHEVM development environment
Doctor,
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::Init { name, template } => {
commands::init::run(&name, template.as_deref()).await
}
Commands::Deploy { chains, contract, dry_run } => {
let chain_list: Vec<&str> = chains.split(',').map(str::trim).collect();
commands::deploy::run(&chain_list, &contract, dry_run).await
}
Commands::Gas { contract, output } => {
commands::gas::run(contract.as_deref(), &output).await
}
Commands::Lint { path, fix, ignore, list_rules } => {
commands::lint::run(&path, fix, ignore, list_rules).await
}
Commands::Doctor => {
commands::doctor::run().await
}
}
}