1use crate::{
2 commands::{
3 policy::PolicyCommand, policy_client::PolicyClientCommand, policy_data::PolicyDataCommand,
4 policy_files::PolicyFilesCommand, regorus::RegorusCommand, 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(|_| "prod".to_string());
96 let service = NewtonCliConfig {
97 eth_rpc_url: "http://127.0.0.1:8545".to_string(),
98 gateway_url: "http://127.0.0.1:8080".to_string(),
99 signer: newton_prover_core::config::key::EcdsaKey {
100 private_key: None,
101 keystore_path: None,
102 keystore_password: None,
103 },
104 };
105 use newton_prover_core::config::{contracts::*, ipfs::IpfsConfig, rpc::ChainRpcProviderConfig};
107 #[allow(clippy::unnecessary_lazy_evaluations)]
110 let contracts = ContractsConfig::load(chain_id, env.clone()).unwrap_or_else(|_| {
111 ContractsConfig {
113 avs: NewtonAvsContractsConfig {
114 newton_prover_service_manager: Address::ZERO,
115 newton_prover_task_manager: Address::ZERO,
116 challenge_verifier: Address::ZERO,
117 rego_verifier: Address::ZERO,
118 attestation_validator: Address::ZERO,
119 operator_registry: Address::ZERO,
120 operator_state_retriever: Address::ZERO,
121 bls_apk_registry: Address::ZERO,
122 index_registry: Address::ZERO,
123 stake_registry: Address::ZERO,
124 socket_registry: Address::ZERO,
125 strategy: Address::ZERO,
126 identity_registry: Address::ZERO,
127 },
128 eigenlayer: EigenlayerContractsConfig {
129 delegation_manager: Address::ZERO,
130 avs_directory: Address::ZERO,
131 strategy_manager: Address::ZERO,
132 allocation_manager: Address::ZERO,
133 rewards_coordinator: Address::ZERO,
134 strategy_factory: Address::ZERO,
135 permission_controller: Address::ZERO,
136 bn254_certificate_verifier: Address::ZERO,
137 key_registrar: Address::ZERO,
138 },
139 destination_multichain: None,
140 policy: NewtonPolicyContractsConfig {
141 policy_factory: Address::ZERO,
142 policy_data_factory: 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: ChainRpcProviderConfig::load(),
152 ipfs: IpfsConfig::default(),
153 contracts,
154 service,
155 data_provider: newton_prover_core::config::DataProviderConfig::default(),
156 }
157 }
158 }
159 }
160
161 fn load_config_required(
164 &self,
165 chain_id: u64,
166 ) -> eyre::Result<newton_prover_core::config::NewtonAvsConfig<NewtonCliConfig>> {
167 let mut builder = NewtonAvsConfigBuilder::new(chain_id);
168 if let Some(config_path) = self.resolve_config_path() {
169 info!("Loading cli config from: {:?}", config_path);
170 builder = builder.with_service_path(config_path);
171 }
172 builder.build::<NewtonCliConfig>().map_err(|e| {
173 eyre::eyre!(
174 "Failed to load configuration: {}. \
175 Make sure deployment files exist for chain_id {} or set DEPLOYMENT_ENV environment variable.",
176 e,
177 chain_id
178 )
179 })
180 }
181
182 pub fn run(self) -> eyre::Result<()> {
184 let env_filter = "warn,newton_cli=info".to_string();
186
187 init_logger(LoggerConfig::new(self.log_format).with_env_filter(env_filter));
189
190 let runner = NewtonRunner::default();
191
192 let commands_that_dont_need_config = matches!(
195 &self.command,
196 Commands::PolicyFiles(_) | Commands::PolicyClient(_) | Commands::Regorus(_)
197 );
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::Regorus(command) => {
225 command.execute().map_err(|e| eyre::eyre!("{}", e))?;
227 }
228 }
229
230 Ok(())
231 }
232}
233
234#[derive(Debug, Subcommand)]
236pub enum Commands {
237 Task(TaskCommand),
239
240 PolicyData(PolicyDataCommand),
242
243 Policy(PolicyCommand),
245
246 PolicyFiles(PolicyFilesCommand),
248
249 #[command(name = "policy-client")]
251 PolicyClient(PolicyClientCommand),
252
253 Regorus(RegorusCommand),
255}