use crate::config::BlueprintManagerContext;
use crate::error::{Error, Result};
use crate::protocol::types::{EigenlayerProtocolEvent, ProtocolEvent};
use alloy_provider::{Provider, ProviderBuilder};
use alloy_rpc_types::{BlockNumberOrTag, Filter};
use blueprint_core::{debug, info, warn};
use blueprint_runner::config::BlueprintEnvironment;
use std::time::Duration;
use tokio::time::sleep;
pub struct EigenlayerProtocolClient {
provider: Box<dyn Provider + Send + Sync>,
last_block: u64,
poll_interval: Duration,
contract_addresses: Vec<alloy_primitives::Address>,
}
impl EigenlayerProtocolClient {
pub async fn new(env: BlueprintEnvironment, _ctx: &BlueprintManagerContext) -> Result<Self> {
let http_rpc_url = env.http_rpc_endpoint.clone();
let provider = ProviderBuilder::new().connect_http(http_rpc_url);
let current_block = provider
.get_block_number()
.await
.map_err(|e| Error::Other(format!("Failed to get current block number: {e}")))?;
info!("EigenLayer client initialized at block {}", current_block);
let contract_addresses = Vec::new();
Ok(Self {
provider: Box::new(provider),
last_block: current_block,
poll_interval: Duration::from_secs(12), contract_addresses,
})
}
async fn poll_next_block(&mut self) -> Result<Option<ProtocolEvent>> {
sleep(self.poll_interval).await;
let latest_block = self
.provider
.get_block_number()
.await
.map_err(|e| Error::Other(format!("Failed to get latest block: {e}")))?;
if latest_block <= self.last_block {
debug!(
"No new blocks (current: {}, latest: {})",
self.last_block, latest_block
);
return Ok(None);
}
let block_number = self.last_block + 1;
self.last_block = block_number;
info!("Processing EigenLayer block {}", block_number);
let block = self
.provider
.get_block_by_number(BlockNumberOrTag::Number(block_number))
.await
.map_err(|e| Error::Other(format!("Failed to get block {}: {e}", block_number)))?
.ok_or_else(|| Error::Other(format!("Block {} not found", block_number)))?;
let block_hash = block.header.hash;
let filter = Filter::new().at_block_hash(block_hash);
let filter = if self.contract_addresses.is_empty() {
filter
} else {
filter.address(self.contract_addresses.clone())
};
let logs = self.provider.get_logs(&filter).await.map_err(|e| {
Error::Other(format!(
"Failed to get logs for block {}: {e}",
block_number
))
})?;
debug!("Found {} logs in block {}", logs.len(), block_number);
Ok(Some(ProtocolEvent::Eigenlayer(EigenlayerProtocolEvent {
block_number,
block_hash: block_hash.0.to_vec(),
logs,
})))
}
}
impl EigenlayerProtocolClient {
pub async fn next_event(&mut self) -> Option<ProtocolEvent> {
loop {
match self.poll_next_block().await {
Ok(Some(event)) => return Some(event),
Ok(None) => {
}
Err(e) => {
warn!("Error polling EigenLayer blocks: {}", e);
sleep(self.poll_interval).await;
}
}
}
}
}