newton_cli/commands/
policy.rs1use alloy::primitives::Address;
2use clap::{Parser, Subcommand};
3use eyre::{Context, Result};
4use newton_prover_chainio::policy::PolicyController;
5use newton_prover_config::NewtonAvsConfig;
6use serde_json::Value;
7use std::path::PathBuf;
8use tracing;
9
10use crate::config::NewtonCliConfig;
11
12#[derive(Debug, Parser)]
14#[command(name = "policy")]
15pub struct PolicyCommand {
16 #[command(subcommand)]
17 pub subcommand: PolicySubcommand,
18}
19
20#[derive(Debug, Subcommand)]
21pub enum PolicySubcommand {
22 Deploy(DeployCommand),
24}
25
26fn validate_non_empty_path(s: &str) -> Result<PathBuf, String> {
27 if s.trim().is_empty() {
28 Err(String::from("Path cannot be empty"))
29 } else {
30 Ok(PathBuf::from(s))
31 }
32}
33
34#[derive(Debug, Parser)]
36pub struct DeployCommand {
37 #[arg(long, env = "PRIVATE_KEY")]
38 private_key: Option<String>,
39
40 #[arg(long, env = "RPC_URL")]
41 rpc_url: Option<String>,
42
43 #[arg(long)]
45 policy_data_address: Address,
46
47 #[arg(long, value_parser = validate_non_empty_path)]
48 policy_cids: PathBuf,
49}
50
51impl DeployCommand {
52 async fn deploy_policy(
57 private_key: &str,
58 rpc_url: &str,
59 policy_cid: &str,
60 schema_cid: &str,
61 entrypoint: &str,
62 policy_data_address: Address,
63 policy_metadata_cid: &str,
64 ) -> Result<Address> {
65 let controller = PolicyController::new(private_key.to_string(), rpc_url.to_string());
66
67 let policy_data = vec![policy_data_address];
69
70 tracing::info!(
71 "Deploying policy with entrypoint: {}, policyCid: {}, schemaCid: {}, policyData: {:?}, metadataCid: {}",
72 entrypoint,
73 policy_cid,
74 schema_cid,
75 policy_data,
76 policy_metadata_cid
77 );
78
79 let (_receipt, policy_address) = controller
80 .deploy_policy(
81 policy_cid.to_string(),
82 schema_cid.to_string(),
83 entrypoint.to_string(),
84 policy_data,
85 policy_metadata_cid.to_string(),
86 )
87 .await
88 .map_err(|e| eyre::eyre!("Failed to deploy policy: {}", e))?;
89
90 tracing::info!("Policy deployed successfully at address: {}", policy_address);
91
92 Ok(policy_address)
93 }
94
95 pub async fn execute(self: Box<Self>, _config: NewtonAvsConfig<NewtonCliConfig>) -> eyre::Result<()> {
97 let private_key = self
99 .private_key
100 .ok_or_else(|| eyre::eyre!("private_key is required (use --private-key or PRIVATE_KEY env var)"))?;
101
102 let rpc_url = self
103 .rpc_url
104 .ok_or_else(|| eyre::eyre!("rpc_url is required (use --rpc-url or RPC_URL env var)"))?;
105
106 let json_content = std::fs::read_to_string(&self.policy_cids)
108 .with_context(|| format!("Failed to read policy_cids.json: {:?}", self.policy_cids))?;
109 let json: Value = serde_json::from_str(&json_content)
110 .with_context(|| format!("Failed to parse policy_cids.json: {:?}", self.policy_cids))?;
111
112 let policy_cid = json.get("policyCid").and_then(|v| v.as_str()).unwrap_or("");
114 let schema_cid = json.get("schemaCid").and_then(|v| v.as_str()).unwrap_or("");
115 let entrypoint = json.get("entrypoint").and_then(|v| v.as_str()).unwrap_or("");
116 let policy_metadata_cid = json.get("policyMetadataCid").and_then(|v| v.as_str()).unwrap_or("");
117
118 let policy_address = Self::deploy_policy(
120 &private_key,
121 &rpc_url,
122 policy_cid,
123 schema_cid,
124 entrypoint,
125 self.policy_data_address,
126 policy_metadata_cid,
127 )
128 .await?;
129
130 tracing::info!("Policy Address: {}", policy_address);
131
132 Ok(())
133 }
134}
135
136impl PolicyCommand {
137 pub async fn execute(self: Box<Self>, config: NewtonAvsConfig<NewtonCliConfig>) -> eyre::Result<()> {
139 match self.subcommand {
140 PolicySubcommand::Deploy(command) => {
141 Box::new(command).execute(config).await?;
142 }
143 }
144 Ok(())
145 }
146}