newton-chainio 0.5.2

newton prover chainio
//! Policy

use crate::error::ChainIoError;
use alloy::{
    primitives::{Address, FixedBytes},
    providers::WalletProvider,
    rpc::types::TransactionReceipt,
};
use eigensdk::common::get_signer;
use newton_core::{
    common::{address::get_policy_factory_address, chain::get_chain_id},
    newton_policy_factory::NewtonPolicyFactory,
};

use tracing::info;

/// AvsWriter struct
#[derive(Debug)]
pub struct PolicyController {
    rpc_url: String,
    signer: String,
}

impl PolicyController {
    /// new instance
    pub fn new(signer: String, rpc_url: String) -> Self {
        PolicyController { signer, rpc_url }
    }

    /// Deploy a new policy
    ///
    /// `policy_code_hash` is `keccak256` of the raw policy program bytes. It MUST match what
    /// the SP1 circuit commits in `RegoContext.policyCodeHash`, otherwise the challenge path
    /// will reject proofs against this policy. Callers should compute it from the bytes they
    /// fetch/pin via `policy_cid`. `NewtonPolicy.initialize` reverts with
    /// `InvalidPolicyCodeHash()` on `FixedBytes::ZERO`.
    pub async fn deploy_policy(
        &self,
        policy_cid: String,
        schema_cid: String,
        entrypoint: String,
        policy_data: Vec<Address>,
        metadata_cid: String,
        policy_code_hash: FixedBytes<32>,
    ) -> Result<(TransactionReceipt, Address), ChainIoError> {
        let wallet = get_signer(&self.signer, &self.rpc_url);
        let wallet_address = wallet.default_signer_address();
        let chain_id = get_chain_id(&self.rpc_url).await;
        let policy_factory_addr = get_policy_factory_address(chain_id).await.unwrap();
        let policy_factory = NewtonPolicyFactory::new(policy_factory_addr, wallet);

        info!(
            "[deploy_policy] entrypoint: {}, policyCid: {}, schemaCid: {}, policy_data: {}",
            entrypoint,
            policy_cid,
            schema_cid,
            policy_data
                .iter()
                .map(|addr| addr.to_string())
                .collect::<Vec<String>>()
                .join(", ")
        );

        let deploy_policy_call = policy_factory.deployPolicy(
            entrypoint,
            policy_cid,
            schema_cid,
            policy_data,
            metadata_cid,
            wallet_address,
            policy_code_hash,
        );

        let deploy_policy_result = deploy_policy_call.send().await;

        match deploy_policy_result {
            Ok(deploy_policy) => {
                let receipt_result = deploy_policy.get_receipt().await;

                match receipt_result {
                    Ok(receipt) => {
                        // Search through all logs to find the PolicyDeployed event
                        let mut policy_address = None;
                        for log in receipt.inner.logs() {
                            if let Ok(policy_deployed) = log.log_decode::<NewtonPolicyFactory::PolicyDeployed>() {
                                let data = policy_deployed.data();
                                policy_address = Some(data.policy);
                                break;
                            }
                        }

                        if let Some(addr) = policy_address {
                            info!("Policy deployed with address: {}", addr);
                            Ok((receipt, addr))
                        } else {
                            Err(ChainIoError::PolicyDeployedEventNotFound)
                        }
                    }

                    Err(e) => Err(ChainIoError::AlloyProviderError(e)),
                }
            }
            Err(e) => Err(ChainIoError::ContractError(e)),
        }
    }
}