1use alloy::primitives::{Address, FixedBytes};
2use clap::{Parser, Subcommand};
3use eyre::{Context, Result};
4use newton_prover_chainio::policy_data::PolicyDataController;
5use newton_prover_core::{
6 common::chain::get_block_time_ms, config::NewtonAvsConfig, newton_policy_data::INewtonPolicyData,
7};
8use serde_json::Value;
9use std::path::PathBuf;
10use tracing::{self, info};
11
12use crate::{commands::utils, config::NewtonCliConfig};
13
14#[derive(Debug, Parser)]
16#[command(name = "policy-data")]
17pub struct PolicyDataCommand {
18 #[command(subcommand)]
19 pub subcommand: PolicyDataSubcommand,
20}
21
22#[derive(Debug, Subcommand)]
23pub enum PolicyDataSubcommand {
24 Deploy(DeployCommand),
26 Simulate(SimulateCommand),
28}
29
30#[derive(Debug, Parser)]
32pub struct SimulateCommand {
33 #[arg(long)]
35 wasm_file: PathBuf,
36
37 #[arg(long)]
39 input_json: String,
40}
41
42#[derive(Debug, Parser)]
44pub struct DeployCommand {
45 #[arg(long, env = "PRIVATE_KEY")]
46 private_key: Option<String>,
47
48 #[arg(long, env = "RPC_URL")]
49 rpc_url: Option<String>,
50
51 #[arg(long, default_value = "policy-files/policy_cids.json")]
52 policy_cids: PathBuf,
53}
54
55impl DeployCommand {
56 async fn seconds_to_blocks(rpc_url: &str, seconds: u32) -> Result<u32> {
58 let block_time_ms = get_block_time_ms(rpc_url).await?;
59 let block_time_seconds = block_time_ms / 1000;
60
61 if block_time_seconds == 0 {
62 return Err(eyre::eyre!("Block time is zero, cannot convert seconds to blocks"));
63 }
64
65 let blocks = (seconds as u64 / block_time_seconds) as u32;
66 tracing::info!(
67 "Converting {} seconds to blocks: block_time={}ms ({}s), result={} blocks",
68 seconds,
69 block_time_ms,
70 block_time_seconds,
71 blocks
72 );
73
74 Ok(blocks)
75 }
76
77 async fn get_task_generator_addresses(_rpc_url: &str) -> Result<Vec<Address>> {
81 let addresses = vec![
82 "0x4883282094755C01cd0d15dFE74753c9E189d194",
83 "0x51eBfB4c0441b0D8898d968975073c24B9190227",
84 "0x19F9dEC9928417B6Ea6aD52291acCa9deef59E3F",
85 "0x9Ccd55A0Fb8aBD14919bb5B2BCDD39C1Dd40E883",
86 "0xb3785B3CA4d6b175518c9a2A51AE836f2dE3016B",
87 "0xC6aA2638873e90eCaF0306cbCC4370C6AC893E68",
88 "0x64E33a6b2874129f2C6FB61832b763F65C8342fb",
89 "0xA21d5CCa5771DAB5a049b1FAA524c41ae911e185",
90 "0x22748005349aD3e261Fc6B1C83956781d6d661B4",
91 "0x3F15Da29D0de8c45bf625299AA20e43970153622",
92 "0x494221AaA9B9B273EB171512Ea000bEaE868d332",
93 "0xD45062003a4626a532F30A4596aB253c45AE0647",
94 ];
95
96 addresses
97 .iter()
98 .map(|addr| {
99 addr.parse()
100 .map_err(|e| eyre::eyre!("Failed to parse task generator address {}: {}", addr, e))
101 })
102 .collect()
103 }
104
105 async fn deploy_policy_data(
111 private_key: &str,
112 rpc_url: &str,
113 wasm_cid: &str,
114 wasm_args_cid: &str,
115 policy_data_metadata_cid: &str,
116 expire_after_blocks: u32,
117 ) -> Result<Address> {
118 let controller = PolicyDataController::new(private_key.to_string(), rpc_url.to_string());
119
120 tracing::info!(
121 "Deploying policy data:\n wasmCid: {}\n wasmArgs: {}\n metadataCid: {}\n expireAfter: {} blocks \n",
122 wasm_cid,
123 wasm_args_cid,
124 policy_data_metadata_cid,
125 expire_after_blocks
126 );
127
128 let (_receipt, policy_data_address) = controller
129 .deploy_policy_data(
130 wasm_cid.to_string(),
131 wasm_args_cid.to_string(),
132 expire_after_blocks,
133 policy_data_metadata_cid.to_string(),
134 )
135 .await
136 .map_err(|e| eyre::eyre!("Failed to deploy policy data: {}", e))?;
137
138 tracing::info!("Policy data deployed successfully at address: {}", policy_data_address);
139
140 Ok(policy_data_address)
141 }
142
143 async fn set_attestation_info(
151 private_key: &str,
152 rpc_url: &str,
153 policy_data_address: Address,
154 attester_address: Address,
155 ) -> Result<()> {
156 let controller = PolicyDataController::new(private_key.to_string(), rpc_url.to_string());
157
158 let task_generator_addresses = Self::get_task_generator_addresses(rpc_url).await?;
160
161 let mut attesters = vec![attester_address];
163 attesters.extend(task_generator_addresses);
164
165 let attestation_info = INewtonPolicyData::AttestationInfo {
167 attesters,
168 attestationType: 0u8, verifier: Address::ZERO,
170 verificationKey: FixedBytes::ZERO,
171 };
172
173 tracing::info!(
174 "Setting attestation info on policy data {} with attesters: {:?}",
175 policy_data_address,
176 attestation_info.attesters
177 );
178
179 controller
180 .set_attestation_info(policy_data_address, attestation_info)
181 .await
182 .map_err(|e| eyre::eyre!("Failed to set attestation info: {}", e))?;
183
184 tracing::info!(
185 "Attestation info set successfully on policy data: {}",
186 policy_data_address
187 );
188
189 Ok(())
190 }
191
192 pub async fn execute(self: Box<Self>, _config: NewtonAvsConfig<NewtonCliConfig>) -> eyre::Result<()> {
194 let private_key = self
196 .private_key
197 .ok_or_else(|| eyre::eyre!("private_key is required (use --private-key or PRIVATE_KEY env var)"))?;
198
199 let rpc_url = self
200 .rpc_url
201 .ok_or_else(|| eyre::eyre!("rpc_url is required (use --rpc-url or RPC_URL env var)"))?;
202
203 let json_content = std::fs::read_to_string(&self.policy_cids)
205 .with_context(|| format!("Failed to read policy_cids.json: {:?}", self.policy_cids))?;
206 let json: Value = serde_json::from_str(&json_content)
207 .with_context(|| format!("Failed to parse policy_cids.json: {:?}", self.policy_cids))?;
208
209 let wasm_cid = json.get("wasmCid").and_then(|v| v.as_str()).unwrap_or("");
211 let wasm_args_cid = json.get("wasmArgs").and_then(|v| v.as_str()).unwrap_or("");
212 let policy_data_metadata_cid = json.get("policyDataMetadataCid").and_then(|v| v.as_str()).unwrap_or("");
213 let attester = json.get("attester").and_then(|v| v.as_str()).unwrap_or("");
214 let attester_address: Address = attester.parse().unwrap_or(Address::ZERO);
215
216 let expire_after_blocks = Self::seconds_to_blocks(&rpc_url, 300).await?;
219
220 let policy_data_address = Self::deploy_policy_data(
222 &private_key,
223 &rpc_url,
224 wasm_cid,
225 wasm_args_cid,
226 policy_data_metadata_cid,
227 expire_after_blocks,
228 )
229 .await?;
230
231 tracing::info!("Policy data deployment completed! Setting attestation info...");
232 Self::set_attestation_info(&private_key, &rpc_url, policy_data_address, attester_address).await?;
234
235 tracing::info!("Successfully deployed policy data and set attestation");
236 tracing::info!("Policy Data Address: {}", policy_data_address);
237
238 Ok(())
239 }
240}
241
242impl SimulateCommand {
243 pub async fn execute(self: Box<Self>, config: NewtonAvsConfig<NewtonCliConfig>) -> eyre::Result<()> {
245 info!("Executing WASM simulation...");
246 let output = utils::execute_wasm(self.wasm_file, self.input_json, config).await?;
247 info!("WASM simulation output: {}", output);
248 Ok(())
249 }
250}
251
252impl PolicyDataCommand {
253 pub async fn execute(self: Box<Self>, config: NewtonAvsConfig<NewtonCliConfig>) -> eyre::Result<()> {
255 match self.subcommand {
256 PolicyDataSubcommand::Deploy(command) => {
257 Box::new(command).execute(config).await?;
258 }
259 PolicyDataSubcommand::Simulate(command) => {
260 Box::new(command).execute(config).await?;
261 }
262 }
263 Ok(())
264 }
265}