blueprint_eigenlayer_extra/
discovery.rs1use crate::error::{EigenlayerExtraError, Result};
9use crate::registration::AvsRegistrationConfig;
10use alloy_primitives::Address;
11use blueprint_core::{info, warn};
12use blueprint_runner::config::BlueprintEnvironment;
13use eigensdk::client_avsregistry::reader::AvsRegistryChainReader;
14use std::path::PathBuf;
15
16pub struct AvsDiscoveryService {
18 env: BlueprintEnvironment,
19}
20
21#[derive(Debug, Clone)]
23pub struct DiscoveredAvs {
24 pub service_manager: Address,
26 pub registry_coordinator: Address,
28 pub operator_state_retriever: Address,
30 pub stake_registry: Address,
32 pub is_registered: bool,
34}
35
36impl AvsDiscoveryService {
37 pub fn new(env: BlueprintEnvironment) -> Self {
39 Self { env }
40 }
41
42 pub async fn discover_avs_registrations(
61 &self,
62 operator_address: Address,
63 ) -> Result<Vec<DiscoveredAvs>> {
64 info!(
65 "Discovering AVS registrations for operator {:#x}",
66 operator_address
67 );
68
69 let contract_addresses = self
70 .env
71 .protocol_settings
72 .eigenlayer()
73 .map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
74
75 let registry_reader = AvsRegistryChainReader::new(
77 contract_addresses.registry_coordinator_address,
78 contract_addresses.operator_state_retriever_address,
79 self.env.http_rpc_endpoint.to_string(),
80 )
81 .await
82 .map_err(|e| {
83 EigenlayerExtraError::Other(format!("Failed to create AVS registry reader: {e}"))
84 })?;
85
86 let is_registered = registry_reader
88 .is_operator_registered(operator_address)
89 .await
90 .map_err(|e| {
91 EigenlayerExtraError::Other(format!("Failed to check registration status: {e}"))
92 })?;
93
94 if !is_registered {
95 info!(
96 "Operator {:#x} is not registered to any AVS",
97 operator_address
98 );
99 return Ok(Vec::new());
100 }
101
102 info!("Operator {:#x} is registered to AVS", operator_address);
103
104 let discovered = DiscoveredAvs {
107 service_manager: contract_addresses.service_manager_address,
108 registry_coordinator: contract_addresses.registry_coordinator_address,
109 operator_state_retriever: contract_addresses.operator_state_retriever_address,
110 stake_registry: contract_addresses.stake_registry_address,
111 is_registered,
112 };
113
114 Ok(vec![discovered])
115 }
116
117 pub async fn is_operator_registered_to_avs(
132 &self,
133 operator_address: Address,
134 registry_coordinator: Address,
135 ) -> Result<bool> {
136 let registry_reader = AvsRegistryChainReader::new(
137 registry_coordinator,
138 Address::ZERO, self.env.http_rpc_endpoint.to_string(),
140 )
141 .await
142 .map_err(|e| {
143 EigenlayerExtraError::Other(format!("Failed to create AVS registry reader: {e}"))
144 })?;
145
146 match registry_reader
147 .is_operator_registered(operator_address)
148 .await
149 {
150 Ok(is_registered) => Ok(is_registered),
151 Err(e) => {
152 warn!(
153 "Failed to query registration for AVS {:#x}: {}",
154 registry_coordinator, e
155 );
156 Ok(false) }
158 }
159 }
160
161 pub fn discovered_to_config(
175 &self,
176 discovered: &DiscoveredAvs,
177 blueprint_path: PathBuf,
178 ) -> Result<AvsRegistrationConfig> {
179 let contract_addresses = self
180 .env
181 .protocol_settings
182 .eigenlayer()
183 .map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
184
185 Ok(AvsRegistrationConfig {
186 service_manager: discovered.service_manager,
187 registry_coordinator: discovered.registry_coordinator,
188 operator_state_retriever: discovered.operator_state_retriever,
189 strategy_manager: contract_addresses.strategy_manager_address,
190 delegation_manager: contract_addresses.delegation_manager_address,
191 avs_directory: contract_addresses.avs_directory_address,
192 rewards_coordinator: contract_addresses.rewards_coordinator_address,
193 permission_controller: contract_addresses.permission_controller_address,
194 allocation_manager: contract_addresses.allocation_manager_address,
195 strategy_address: contract_addresses.strategy_address,
196 stake_registry: discovered.stake_registry,
197 blueprint_path,
198 container_image: None, runtime_target: crate::RuntimeTarget::default(), allocation_delay: contract_addresses.allocation_delay,
201 deposit_amount: contract_addresses.deposit_amount,
202 stake_amount: contract_addresses.stake_amount,
203 operator_sets: contract_addresses.operator_sets.clone(),
204 })
205 }
206
207 pub async fn get_operator_status(
220 &self,
221 operator_address: Address,
222 registry_coordinator: Address,
223 ) -> Result<OperatorStatus> {
224 let registry_reader = AvsRegistryChainReader::new(
225 registry_coordinator,
226 Address::ZERO,
227 self.env.http_rpc_endpoint.to_string(),
228 )
229 .await
230 .map_err(|e| {
231 EigenlayerExtraError::Other(format!("Failed to create AVS registry reader: {e}"))
232 })?;
233
234 let is_registered = registry_reader
235 .is_operator_registered(operator_address)
236 .await
237 .map_err(|e| {
238 EigenlayerExtraError::Other(format!("Failed to query operator status: {e}"))
239 })?;
240
241 Ok(OperatorStatus {
242 operator_address,
243 registry_coordinator,
244 is_registered,
245 })
246 }
247}
248
249#[derive(Debug, Clone)]
251pub struct OperatorStatus {
252 pub operator_address: Address,
254 pub registry_coordinator: Address,
256 pub is_registered: bool,
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn test_operator_status_creation() {
266 let operator = Address::from([1u8; 20]);
267 let registry = Address::from([2u8; 20]);
268
269 let status = OperatorStatus {
270 operator_address: operator,
271 registry_coordinator: registry,
272 is_registered: true,
273 };
274
275 assert_eq!(status.operator_address, operator);
276 assert_eq!(status.registry_coordinator, registry);
277 assert!(status.is_registered);
278 }
279}