csv-adapter-ethereum 0.1.1

Ethereum adapter for CSV (Client-Side Validation) with storage slot seals and light-client proofs
Documentation
//! Ethereum adapter configuration

/// Configuration for the Ethereum anchor layer
#[derive(Clone, Debug)]
pub struct EthereumConfig {
    /// Ethereum network (mainnet, goerli, sepolia, etc.)
    pub network: Network,
    /// Required confirmation depth for probabilistic finality
    pub finality_depth: u64,
    /// Whether to use post-merge finalized checkpoints
    pub use_checkpoint_finality: bool,
    /// RPC endpoint URL
    pub rpc_url: String,
}

/// Ethereum network type
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Network {
    /// Ethereum mainnet
    Mainnet,
    /// Goerli testnet
    Goerli,
    /// Sepolia testnet
    Sepolia,
    /// Local development
    Dev,
}

impl Network {
    /// Get chain ID for the network
    pub fn chain_id(&self) -> u64 {
        match self {
            Network::Mainnet => 1,
            Network::Goerli => 5,
            Network::Sepolia => 11155111,
            Network::Dev => 1337,
        }
    }
}

impl EthereumConfig {
    /// Validate configuration values
    pub fn validate(&self) -> Result<String, String> {
        if self.rpc_url.is_empty() {
            return Err("rpc_url cannot be empty".to_string());
        }
        if self.finality_depth == 0 {
            return Err("finality_depth must be greater than 0".to_string());
        }
        if self.finality_depth > 10000 {
            return Err("finality_depth must be <= 10000".to_string());
        }
        if self.network == Network::Mainnet && self.rpc_url.contains("127.0.0.1") {
            return Err("mainnet config should not use localhost rpc_url".to_string());
        }
        Ok("Configuration is valid".to_string())
    }
}

impl Default for EthereumConfig {
    fn default() -> Self {
        Self {
            network: Network::Sepolia,
            finality_depth: 15,
            use_checkpoint_finality: true,
            rpc_url: "http://127.0.0.1:8545".to_string(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_default_config() {
        let config = EthereumConfig::default();
        assert_eq!(config.network, Network::Sepolia);
        assert_eq!(config.finality_depth, 15);
        assert!(config.use_checkpoint_finality);
        assert!(config.validate().is_ok());
    }

    #[test]
    fn test_config_validate_empty_rpc_url() {
        let mut config = EthereumConfig::default();
        config.rpc_url = String::new();
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_config_validate_zero_finality_depth() {
        let mut config = EthereumConfig::default();
        config.finality_depth = 0;
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_config_validate_mainnet_localhost() {
        let mut config = EthereumConfig::default();
        config.network = Network::Mainnet;
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_network_chain_id() {
        assert_eq!(Network::Mainnet.chain_id(), 1);
        assert_eq!(Network::Sepolia.chain_id(), 11155111);
    }
}