blueprint_eigenlayer_extra/services/
slashing.rs1use crate::error::{EigenlayerExtraError, Result};
2use alloy_primitives::Address;
3use blueprint_core::info;
4use blueprint_keystore::backends::Backend;
5use blueprint_keystore::backends::ecdsa::EcdsaBackend;
6use blueprint_keystore::crypto::k256::K256Ecdsa;
7use blueprint_runner::config::BlueprintEnvironment;
8use eigensdk::utils::slashing::core::delegation_manager::DelegationManager;
9
10#[derive(Debug, Clone)]
12pub struct SlashingStatus {
13 pub is_slashed: bool,
15 pub operator_address: Address,
17}
18
19#[derive(Debug, Clone)]
21pub struct SlashingEvent {
22 pub operator_address: Address,
24 pub strategy_address: Address,
26 pub amount: alloy_primitives::U256,
28 pub block_number: u64,
30}
31
32#[derive(Clone)]
37pub struct SlashingMonitor {
38 env: BlueprintEnvironment,
39}
40
41impl SlashingMonitor {
42 pub fn new(env: BlueprintEnvironment) -> Self {
44 Self { env }
45 }
46
47 fn get_operator_address(&self) -> Result<Address> {
53 let ecdsa_public = self
54 .env
55 .keystore()
56 .first_local::<K256Ecdsa>()
57 .map_err(EigenlayerExtraError::Keystore)?;
58
59 let ecdsa_secret = self
60 .env
61 .keystore()
62 .expose_ecdsa_secret(&ecdsa_public)
63 .map_err(EigenlayerExtraError::Keystore)?
64 .ok_or_else(|| {
65 EigenlayerExtraError::InvalidConfiguration("No ECDSA secret found".into())
66 })?;
67
68 ecdsa_secret
69 .alloy_address()
70 .map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))
71 }
72
73 pub async fn is_operator_slashed(&self) -> Result<bool> {
80 let operator_address = self.get_operator_address()?;
81 let contract_addresses = self
82 .env
83 .protocol_settings
84 .eigenlayer()
85 .map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
86
87 let provider =
88 blueprint_evm_extra::util::get_provider_http(self.env.http_rpc_endpoint.clone());
89
90 let delegation_manager = DelegationManager::DelegationManagerInstance::new(
91 contract_addresses.delegation_manager_address,
92 provider,
93 );
94
95 let is_operator = delegation_manager
97 .isOperator(operator_address)
98 .call()
99 .await
100 .map_err(|e| EigenlayerExtraError::Contract(e.to_string()))?;
101
102 Ok(!is_operator)
104 }
105
106 pub async fn get_slashing_status(&self) -> Result<SlashingStatus> {
113 let operator_address = self.get_operator_address()?;
114 let is_slashed = self.is_operator_slashed().await?;
115
116 Ok(SlashingStatus {
117 is_slashed,
118 operator_address,
119 })
120 }
121
122 pub async fn get_slashable_shares(
135 &self,
136 strategy_address: Address,
137 ) -> Result<alloy_primitives::U256> {
138 let operator_address = self.get_operator_address()?;
139 let contract_addresses = self
140 .env
141 .protocol_settings
142 .eigenlayer()
143 .map_err(|e| EigenlayerExtraError::InvalidConfiguration(e.to_string()))?;
144
145 let provider =
146 blueprint_evm_extra::util::get_provider_http(self.env.http_rpc_endpoint.clone());
147
148 let delegation_manager = DelegationManager::DelegationManagerInstance::new(
149 contract_addresses.delegation_manager_address,
150 provider,
151 );
152
153 let result = delegation_manager
154 .getSlashableSharesInQueue(operator_address, strategy_address)
155 .call()
156 .await
157 .map_err(|e| EigenlayerExtraError::Contract(e.to_string()))?;
158
159 info!(
160 "Slashable shares for operator {} in strategy {}: {}",
161 operator_address, strategy_address, result
162 );
163
164 Ok(result)
165 }
166}
167
168#[cfg(test)]
169mod tests {
170
171 #[tokio::test]
172 #[ignore] async fn test_slashing_monitor_creation() {
174 }
177}