1use crate::{
2 commands::{
3 newton_dashboard::NewtonDashboardCommand, policy::PolicyCommand, policy_client::PolicyClientCommand,
4 policy_data::PolicyDataCommand, policy_files::PolicyFilesCommand, task::TaskCommand,
5 },
6 config::NewtonCliConfig,
7};
8use alloy::primitives::Address;
9use clap::{Parser, Subcommand};
10use newton_cli_runner::NewtonRunner;
11use newton_prover_core::config::{
12 log::{init_logger, LogFormat, LoggerConfig},
13 NewtonAvsConfigBuilder,
14};
15use std::{ffi::OsString, path::PathBuf};
16use tracing::info;
17
18#[derive(Debug, Parser)]
20#[command(author, about = "Newton protocol cli", long_about = None)]
21pub struct NewtonCli {
22 #[arg(long, value_name = "CHAIN_ID", global = true, env = "CHAIN_ID")]
24 chain_id: Option<u64>,
25
26 #[arg(long, value_name = "FILE", global = true)]
28 config_path: Option<PathBuf>,
29
30 #[arg(
32 long,
33 value_enum,
34 default_value = "minimal",
35 global = true,
36 help = "Log format: full, compact, pretty, json, or minimal"
37 )]
38 log_format: LogFormat,
39
40 #[arg(long, global = true)]
42 quiet: bool,
43
44 #[command(subcommand)]
45 command: Commands,
46}
47
48impl NewtonCli {
49 pub fn parse_args() -> Self {
51 Self::parse()
52 }
53
54 pub fn try_parse_args_from<I, T>(itr: I) -> Result<Self, clap::error::Error>
56 where
57 I: IntoIterator<Item = T>,
58 T: Into<OsString> + Clone,
59 {
60 Self::try_parse_from(itr)
61 }
62
63 fn resolve_config_path(&self) -> Option<PathBuf> {
65 if let Some(path) = &self.config_path {
66 Some(path.clone())
67 } else {
68 let home = std::env::var("HOME").ok()?;
69 let path = std::path::PathBuf::from(home).join(".newton").join("newton-cli.toml");
70 if path.exists() {
71 Some(path)
72 } else {
73 None
74 }
75 }
76 }
77
78 fn load_config_or_minimal(&self, chain_id: u64) -> newton_prover_core::config::NewtonAvsConfig<NewtonCliConfig> {
82 let mut builder = NewtonAvsConfigBuilder::new(chain_id);
83 if let Some(config_path) = self.resolve_config_path() {
84 info!("Loading cli config from: {:?}", config_path);
85 builder = builder.with_service_path(config_path);
86 }
87
88 match builder.build::<NewtonCliConfig>() {
90 Ok(config) => config,
91 Err(e) => {
92 tracing::debug!("Service config loading failed, using defaults: {}", e);
95 let env = std::env::var("DEPLOYMENT_ENV").unwrap_or_else(|_| "stagef".to_string());
96 let service = NewtonCliConfig {
97 eth_rpc_url: "http://127.0.0.1:8545".to_string(),
98 newton_rpc_url: "http://127.0.0.1:8545".to_string(),
99 signer: newton_prover_core::config::key::EcdsaKey {
100 private_key: None,
101 keystore_path: None,
102 keystore_password: None,
103 },
104 dashboard_bearer_token: None,
105 dashboard_api_base_url: None,
106 user_secret_key: None,
107 };
108 use newton_prover_core::config::{contracts::*, ipfs::IpfsConfig, rpc::RpcProviderConfig};
110 #[allow(clippy::unnecessary_lazy_evaluations)]
113 let contracts = ContractsConfig::load(chain_id, env.clone()).unwrap_or_else(|_| {
114 ContractsConfig {
116 avs: NewtonAvsContractsConfig {
117 newton_prover_service_manager: Address::ZERO,
118 newton_prover_task_manager: Address::ZERO,
119 challenge_verifier: Address::ZERO,
120 rego_verifier: Address::ZERO,
121 attestation_validator: Address::ZERO,
122 operator_registry: Address::ZERO,
123 operator_state_retriever: Address::ZERO,
124 bls_apk_registry: Address::ZERO,
125 index_registry: Address::ZERO,
126 stake_registry: Address::ZERO,
127 socket_registry: Address::ZERO,
128 strategy: Address::ZERO,
129 operator_table_updater: Address::ZERO,
130 },
131 eigenlayer: EigenlayerContractsConfig {
132 delegation_manager: Address::ZERO,
133 avs_directory: Address::ZERO,
134 strategy_manager: Address::ZERO,
135 allocation_manager: Address::ZERO,
136 rewards_coordinator: Address::ZERO,
137 strategy_factory: Address::ZERO,
138 permission_controller: Address::ZERO,
139 operator_table_updater: Address::ZERO,
140 ecdsa_certificate_verifier: Address::ZERO,
141 bn254_certificate_verifier: Address::ZERO,
142 },
143 policy: NewtonPolicyContractsConfig {
144 policy_factory: Address::ZERO,
145 policy_data_factory: Address::ZERO,
146 },
147 }
148 });
149 newton_prover_core::config::NewtonAvsConfig {
151 env: env.clone(),
152 chain_id,
153 source_chain_id: None,
154 source_rpc: None,
155 rpc: RpcProviderConfig::load(chain_id).unwrap_or(RpcProviderConfig {
156 http: "http://127.0.0.1:8545".to_string(),
157 ws: "ws://127.0.0.1:8545".to_string(),
158 }),
159 ipfs: IpfsConfig::default(),
160 contracts,
161 service,
162 }
163 }
164 }
165 }
166
167 fn load_config_required(
170 &self,
171 chain_id: u64,
172 ) -> eyre::Result<newton_prover_core::config::NewtonAvsConfig<NewtonCliConfig>> {
173 let mut builder = NewtonAvsConfigBuilder::new(chain_id);
174 if let Some(config_path) = self.resolve_config_path() {
175 info!("Loading cli config from: {:?}", config_path);
176 builder = builder.with_service_path(config_path);
177 }
178 builder.build::<NewtonCliConfig>().map_err(|e| {
179 eyre::eyre!(
180 "Failed to load configuration: {}. \
181 Make sure deployment files exist for chain_id {} or set DEPLOYMENT_ENV environment variable.",
182 e,
183 chain_id
184 )
185 })
186 }
187
188 pub fn run(self) -> eyre::Result<()> {
190 let env_filter = "warn,newton_cli=info".to_string();
192
193 init_logger(LoggerConfig::new(self.log_format).with_env_filter(env_filter));
195
196 let runner = NewtonRunner::default();
197
198 let commands_that_dont_need_config =
201 matches!(&self.command, Commands::PolicyFiles(_) | Commands::PolicyClient(_));
202
203 let chain_id = if commands_that_dont_need_config {
205 self.chain_id.unwrap_or(1)
206 } else {
207 self.chain_id.ok_or_else(|| eyre::eyre!("chain id is required"))?
208 };
209
210 let config = if commands_that_dont_need_config {
216 self.load_config_or_minimal(chain_id)
217 } else {
218 self.load_config_required(chain_id)?
220 };
221
222 match self.command {
223 Commands::Task(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
224 Commands::PolicyData(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
225 Commands::Policy(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
226 Commands::PolicyFiles(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
227 Commands::PolicyClient(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
228 Commands::NewtonDashboard(command) => {
229 runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?
230 }
231 }
232
233 Ok(())
234 }
235}
236
237#[derive(Debug, Subcommand)]
239pub enum Commands {
240 Task(TaskCommand),
242
243 PolicyData(PolicyDataCommand),
245
246 Policy(PolicyCommand),
248
249 PolicyFiles(PolicyFilesCommand),
251
252 #[command(name = "policy-client")]
254 PolicyClient(PolicyClientCommand),
255
256 #[command(name = "newton-dashboard")]
258 NewtonDashboard(NewtonDashboardCommand),
259}