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