use crate::error::{EigenlayerExtraError, Result};
use crate::registration::AvsRegistrationConfig;
use alloy_primitives::Address;
use blueprint_core::{info, warn};
use blueprint_runner::config::BlueprintEnvironment;
use eigensdk::client_avsregistry::reader::AvsRegistryChainReader;
use std::path::PathBuf;
pub struct AvsDiscoveryService {
env: BlueprintEnvironment,
}
#[derive(Debug, Clone)]
pub struct DiscoveredAvs {
pub service_manager: Address,
pub registry_coordinator: Address,
pub operator_state_retriever: Address,
pub stake_registry: Address,
pub is_registered: bool,
}
impl AvsDiscoveryService {
pub fn new(env: BlueprintEnvironment) -> Self {
Self { env }
}
pub async fn discover_avs_registrations(
&self,
operator_address: Address,
) -> Result<Vec<DiscoveredAvs>> {
info!(
"Discovering AVS registrations for operator {:#x}",
operator_address
);
let contract_addresses = self
.env
.protocol_settings
.eigenlayer()
.map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
let registry_reader = AvsRegistryChainReader::new(
contract_addresses.registry_coordinator_address,
contract_addresses.operator_state_retriever_address,
self.env.http_rpc_endpoint.to_string(),
)
.await
.map_err(|e| {
EigenlayerExtraError::Other(format!("Failed to create AVS registry reader: {e}"))
})?;
let is_registered = registry_reader
.is_operator_registered(operator_address)
.await
.map_err(|e| {
EigenlayerExtraError::Other(format!("Failed to check registration status: {e}"))
})?;
if !is_registered {
info!(
"Operator {:#x} is not registered to any AVS",
operator_address
);
return Ok(Vec::new());
}
info!("Operator {:#x} is registered to AVS", operator_address);
let discovered = DiscoveredAvs {
service_manager: contract_addresses.service_manager_address,
registry_coordinator: contract_addresses.registry_coordinator_address,
operator_state_retriever: contract_addresses.operator_state_retriever_address,
stake_registry: contract_addresses.stake_registry_address,
is_registered,
};
Ok(vec![discovered])
}
pub async fn is_operator_registered_to_avs(
&self,
operator_address: Address,
registry_coordinator: Address,
) -> Result<bool> {
let registry_reader = AvsRegistryChainReader::new(
registry_coordinator,
Address::ZERO, self.env.http_rpc_endpoint.to_string(),
)
.await
.map_err(|e| {
EigenlayerExtraError::Other(format!("Failed to create AVS registry reader: {e}"))
})?;
match registry_reader
.is_operator_registered(operator_address)
.await
{
Ok(is_registered) => Ok(is_registered),
Err(e) => {
warn!(
"Failed to query registration for AVS {:#x}: {}",
registry_coordinator, e
);
Ok(false) }
}
}
pub fn discovered_to_config(
&self,
discovered: &DiscoveredAvs,
blueprint_path: PathBuf,
) -> Result<AvsRegistrationConfig> {
let contract_addresses = self
.env
.protocol_settings
.eigenlayer()
.map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
Ok(AvsRegistrationConfig {
service_manager: discovered.service_manager,
registry_coordinator: discovered.registry_coordinator,
operator_state_retriever: discovered.operator_state_retriever,
strategy_manager: contract_addresses.strategy_manager_address,
delegation_manager: contract_addresses.delegation_manager_address,
avs_directory: contract_addresses.avs_directory_address,
rewards_coordinator: contract_addresses.rewards_coordinator_address,
permission_controller: contract_addresses.permission_controller_address,
allocation_manager: contract_addresses.allocation_manager_address,
strategy_address: contract_addresses.strategy_address,
stake_registry: discovered.stake_registry,
blueprint_path,
container_image: None, runtime_target: crate::RuntimeTarget::default(), allocation_delay: contract_addresses.allocation_delay,
deposit_amount: contract_addresses.deposit_amount,
stake_amount: contract_addresses.stake_amount,
operator_sets: contract_addresses.operator_sets.clone(),
})
}
pub async fn get_operator_status(
&self,
operator_address: Address,
registry_coordinator: Address,
) -> Result<OperatorStatus> {
let registry_reader = AvsRegistryChainReader::new(
registry_coordinator,
Address::ZERO,
self.env.http_rpc_endpoint.to_string(),
)
.await
.map_err(|e| {
EigenlayerExtraError::Other(format!("Failed to create AVS registry reader: {e}"))
})?;
let is_registered = registry_reader
.is_operator_registered(operator_address)
.await
.map_err(|e| {
EigenlayerExtraError::Other(format!("Failed to query operator status: {e}"))
})?;
Ok(OperatorStatus {
operator_address,
registry_coordinator,
is_registered,
})
}
}
#[derive(Debug, Clone)]
pub struct OperatorStatus {
pub operator_address: Address,
pub registry_coordinator: Address,
pub is_registered: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_operator_status_creation() {
let operator = Address::from([1u8; 20]);
let registry = Address::from([2u8; 20]);
let status = OperatorStatus {
operator_address: operator,
registry_coordinator: registry,
is_registered: true,
};
assert_eq!(status.operator_address, operator);
assert_eq!(status.registry_coordinator, registry);
assert!(status.is_registered);
}
}