use crate::error::{EigenlayerExtraError, Result};
use alloy_primitives::Address;
use blueprint_core::info;
use blueprint_keystore::backends::Backend;
use blueprint_keystore::backends::eigenlayer::EigenlayerBackend;
use blueprint_keystore::crypto::k256::K256Ecdsa;
use blueprint_runner::config::BlueprintEnvironment;
use eigensdk::utils::slashing::core::delegation_manager::DelegationManager;
#[derive(Debug, Clone)]
pub struct SlashingStatus {
pub is_slashed: bool,
pub operator_address: Address,
}
#[derive(Debug, Clone)]
pub struct SlashingEvent {
pub operator_address: Address,
pub strategy_address: Address,
pub amount: alloy_primitives::U256,
pub block_number: u64,
}
#[derive(Clone)]
pub struct SlashingMonitor {
env: BlueprintEnvironment,
}
impl SlashingMonitor {
pub fn new(env: BlueprintEnvironment) -> Self {
Self { env }
}
fn get_operator_address(&self) -> Result<Address> {
let ecdsa_public = self
.env
.keystore()
.first_local::<K256Ecdsa>()
.map_err(EigenlayerExtraError::Keystore)?;
let ecdsa_secret = self
.env
.keystore()
.expose_ecdsa_secret(&ecdsa_public)
.map_err(EigenlayerExtraError::Keystore)?
.ok_or_else(|| {
EigenlayerExtraError::InvalidConfiguration("No ECDSA secret found".into())
})?;
ecdsa_secret
.alloy_address()
.map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))
}
pub async fn is_operator_slashed(&self) -> Result<bool> {
let operator_address = self.get_operator_address()?;
let contract_addresses = self
.env
.protocol_settings
.eigenlayer()
.map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
let provider =
blueprint_evm_extra::util::get_provider_http(self.env.http_rpc_endpoint.clone());
let delegation_manager = DelegationManager::DelegationManagerInstance::new(
contract_addresses.delegation_manager_address,
provider,
);
let is_operator = delegation_manager
.isOperator(operator_address)
.call()
.await
.map_err(|e| EigenlayerExtraError::Contract(e.to_string()))?;
Ok(!is_operator)
}
pub async fn get_slashing_status(&self) -> Result<SlashingStatus> {
let operator_address = self.get_operator_address()?;
let is_slashed = self.is_operator_slashed().await?;
Ok(SlashingStatus {
is_slashed,
operator_address,
})
}
pub async fn get_slashable_shares(
&self,
strategy_address: Address,
) -> Result<alloy_primitives::U256> {
let operator_address = self.get_operator_address()?;
let contract_addresses = self
.env
.protocol_settings
.eigenlayer()
.map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
let provider =
blueprint_evm_extra::util::get_provider_http(self.env.http_rpc_endpoint.clone());
let delegation_manager = DelegationManager::DelegationManagerInstance::new(
contract_addresses.delegation_manager_address,
provider,
);
let result = delegation_manager
.getSlashableSharesInQueue(operator_address, strategy_address)
.call()
.await
.map_err(|e| EigenlayerExtraError::Contract(e.to_string()))?;
info!(
"Slashable shares for operator {} in strategy {}: {}",
operator_address, strategy_address, result
);
Ok(result)
}
}
#[cfg(test)]
mod tests {
#[tokio::test]
#[ignore] async fn test_slashing_monitor_creation() {
}
}