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(|_| "stagef".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 },
127 eigenlayer: EigenlayerContractsConfig {
128 delegation_manager: Address::ZERO,
129 avs_directory: Address::ZERO,
130 strategy_manager: Address::ZERO,
131 allocation_manager: Address::ZERO,
132 rewards_coordinator: Address::ZERO,
133 strategy_factory: Address::ZERO,
134 permission_controller: Address::ZERO,
135 bn254_certificate_verifier: Address::ZERO,
136 key_registrar: Address::ZERO,
137 },
138 destination_multichain: None,
139 policy: NewtonPolicyContractsConfig {
140 policy_factory: Address::ZERO,
141 policy_data_factory: Address::ZERO,
142 },
143 }
144 });
145 newton_prover_core::config::NewtonAvsConfig {
147 env: env.clone(),
148 chain_id,
149 source_chain_id: None,
150 rpc: ChainRpcProviderConfig::load(),
151 ipfs: IpfsConfig::default(),
152 contracts,
153 service,
154 data_provider: newton_prover_core::config::DataProviderConfig::default(),
155 }
156 }
157 }
158 }
159
160 fn load_config_required(
163 &self,
164 chain_id: u64,
165 ) -> eyre::Result<newton_prover_core::config::NewtonAvsConfig<NewtonCliConfig>> {
166 let mut builder = NewtonAvsConfigBuilder::new(chain_id);
167 if let Some(config_path) = self.resolve_config_path() {
168 info!("Loading cli config from: {:?}", config_path);
169 builder = builder.with_service_path(config_path);
170 }
171 builder.build::<NewtonCliConfig>().map_err(|e| {
172 eyre::eyre!(
173 "Failed to load configuration: {}. \
174 Make sure deployment files exist for chain_id {} or set DEPLOYMENT_ENV environment variable.",
175 e,
176 chain_id
177 )
178 })
179 }
180
181 pub fn run(self) -> eyre::Result<()> {
183 let env_filter = "warn,newton_cli=info".to_string();
185
186 init_logger(LoggerConfig::new(self.log_format).with_env_filter(env_filter));
188
189 let runner = NewtonRunner::default();
190
191 let commands_that_dont_need_config = matches!(
194 &self.command,
195 Commands::PolicyFiles(_) | Commands::PolicyClient(_) | Commands::Regorus(_)
196 );
197
198 let chain_id = if commands_that_dont_need_config {
200 self.chain_id.unwrap_or(1)
201 } else {
202 self.chain_id.ok_or_else(|| eyre::eyre!("chain id is required"))?
203 };
204
205 let config = if commands_that_dont_need_config {
211 self.load_config_or_minimal(chain_id)
212 } else {
213 self.load_config_required(chain_id)?
215 };
216
217 match self.command {
218 Commands::Task(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
219 Commands::PolicyData(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
220 Commands::Policy(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
221 Commands::PolicyFiles(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
222 Commands::PolicyClient(command) => runner.run_blocking_until_ctrl_c(Box::new(command).execute(config))?,
223 Commands::Regorus(command) => {
224 command.execute().map_err(|e| eyre::eyre!("{}", e))?;
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 Regorus(RegorusCommand),
254}