blueprint_eigenlayer_testing_utils/
harness.rs1use crate::Error;
2use crate::env::setup_eigenlayer_test_environment;
3use alloy_primitives::address;
4use alloy_primitives::{Address, U256};
5use alloy_provider::Provider;
6use blueprint_auth::db::RocksDb;
7use blueprint_chain_setup::anvil::keys::inject_anvil_key;
8use blueprint_chain_setup::anvil::{AnvilTestnet, Container};
9use blueprint_core::{error, info};
10use blueprint_evm_extra::util::get_provider_http;
11use blueprint_manager_bridge::server::{Bridge, BridgeHandle};
12use blueprint_runner::config::{BlueprintEnvironment, ContextConfig, SupportedChains};
13use blueprint_runner::eigenlayer::config::EigenlayerProtocolSettings;
14use eigenlayer_contract_deployer::core::{
15 DelegationManagerConfig, DeployedCoreContracts, DeploymentConfigData, EigenPodManagerConfig,
16 RewardsCoordinatorConfig, StrategyFactoryConfig, StrategyManagerConfig,
17};
18use std::future::Future;
19use std::net::Ipv4Addr;
20use std::path::PathBuf;
21use tempfile::TempDir;
22use tokio::task::JoinHandle;
23use url::Url;
24
25pub struct EigenlayerTestHarness {
27 env: BlueprintEnvironment,
28 _temp_dir: TempDir,
29 _container: Container,
30 _auth_proxy: JoinHandle<Result<(), Error>>,
31 _bridge: BridgeHandle,
32}
33
34impl EigenlayerTestHarness {
35 pub async fn setup(
45 owner_private_key: &str,
46 test_dir: TempDir,
47 testnet: AnvilTestnet,
48 eigenlayer_protocol_settings: Option<EigenlayerProtocolSettings>,
49 ) -> Result<Self, Error> {
50 Self::setup_with_context(
51 owner_private_key,
52 test_dir,
53 testnet,
54 eigenlayer_protocol_settings,
55 )
56 .await
57 }
58}
59
60impl EigenlayerTestHarness {
61 pub async fn setup_with_context(
77 owner_private_key: &str,
78 test_dir: TempDir,
79 testnet: AnvilTestnet,
80 eigenlayer_protocol_settings: Option<EigenlayerProtocolSettings>,
81 ) -> Result<Self, Error> {
82 let keystore_path = test_dir.path().join("keystore");
84 inject_anvil_key(&keystore_path, owner_private_key)?;
85
86 let eigenlayer_protocol_settings = match eigenlayer_protocol_settings {
87 Some(settings) => settings,
88 None => setup_eigenlayer_test_environment(testnet.http_endpoint.clone()).await,
89 };
90
91 let data_dir = test_dir.path().join("data");
92 tokio::fs::create_dir_all(&data_dir).await?;
93
94 const DEFAULT_AUTH_PROXY_PORT: u16 = 50051;
96 let (auth_proxy_db, auth_proxy_task) =
97 run_auth_proxy(test_dir.path().to_path_buf(), DEFAULT_AUTH_PROXY_PORT).await?;
98
99 let auth_proxy = tokio::spawn(auth_proxy_task);
100
101 let runtime_dir = test_dir.path().join("runtime");
103 tokio::fs::create_dir_all(&runtime_dir).await?;
104
105 let bridge = Bridge::new(runtime_dir, String::from("service"), auth_proxy_db, true);
106 let bridge_socket_path = bridge.base_socket_path();
107
108 let (bridge_handle, _alive_rx) = bridge.spawn()?;
109
110 let context_config = ContextConfig::create_eigenlayer_config(
112 testnet.http_endpoint.clone(),
113 testnet.ws_endpoint.clone(),
114 keystore_path.to_string_lossy().into_owned(),
115 None,
116 data_dir,
117 None,
118 SupportedChains::LocalTestnet,
119 eigenlayer_protocol_settings,
120 );
121
122 let mut env = BlueprintEnvironment::load_with_config(context_config)
124 .map_err(|e| Error::Setup(e.to_string()))?;
125
126 env.bridge_socket_path = Some(bridge_socket_path);
127 env.test_mode = true;
128
129 Ok(Self {
130 env,
131 _temp_dir: test_dir,
132 _container: testnet.container,
133 _auth_proxy: auth_proxy,
134 _bridge: bridge_handle,
135 })
136 }
137
138 #[must_use]
139 pub fn env(&self) -> &BlueprintEnvironment {
140 &self.env
141 }
142}
143
144#[must_use]
150pub async fn get_accounts(http_endpoint: Url) -> Vec<Address> {
151 let provider = get_provider_http(http_endpoint.clone());
152 provider.get_accounts().await.unwrap()
153}
154
155#[must_use]
157pub fn get_owner_account(accounts: &[Address]) -> Address {
158 accounts[0]
159}
160
161#[must_use]
163pub fn get_aggregator_account(accounts: &[Address]) -> Address {
164 accounts[9]
165}
166
167#[must_use]
169pub fn get_task_generator_account(accounts: &[Address]) -> Address {
170 accounts[4]
171}
172
173async fn run_auth_proxy(
190 data_dir: PathBuf,
191 auth_proxy_port: u16,
192) -> Result<(RocksDb, impl Future<Output = Result<(), Error>>), Error> {
193 let db_path = data_dir.join("private").join("auth-proxy").join("db");
194 tokio::fs::create_dir_all(&db_path).await?;
195
196 let proxy = blueprint_auth::proxy::AuthenticatedProxy::new(&db_path)?;
197 let db = proxy.db();
198
199 let task = async move {
200 let router = proxy.router();
201 let listener =
202 tokio::net::TcpListener::bind((Ipv4Addr::LOCALHOST, auth_proxy_port)).await?;
203 info!(
204 "Auth proxy listening on {}:{}",
205 Ipv4Addr::LOCALHOST,
206 auth_proxy_port
207 );
208 let result = axum::serve(listener, router).await;
209 if let Err(err) = result {
210 error!("Auth proxy error: {err}");
211 }
212
213 Ok(())
214 };
215
216 Ok((db, task))
217}
218
219pub async fn deploy_eigenlayer_core_contracts(
239 http_endpoint: &str,
240 owner_private_key: &str,
241 owner_account: Address,
242) -> Result<DeployedCoreContracts, Error> {
243 let core_config = DeploymentConfigData {
244 strategy_manager: StrategyManagerConfig {
245 init_paused_status: U256::from(0),
246 init_withdrawal_delay_blocks: 1u32,
247 },
248 delegation_manager: DelegationManagerConfig {
249 init_paused_status: U256::from(0),
250 withdrawal_delay_blocks: 0u32,
251 },
252 eigen_pod_manager: EigenPodManagerConfig {
253 init_paused_status: U256::from(0),
254 },
255 rewards_coordinator: RewardsCoordinatorConfig {
256 init_paused_status: U256::from(0),
257 max_rewards_duration: 864_000u32,
258 max_retroactive_length: 432_000u32,
259 max_future_length: 86_400u32,
260 genesis_rewards_timestamp: 1_672_531_200_u32,
261 updater: owner_account,
262 activation_delay: 0u32,
263 calculation_interval_seconds: 86_400u32,
264 global_operator_commission_bips: 1_000u16,
265 },
266 strategy_factory: StrategyFactoryConfig {
267 init_paused_status: U256::from(0),
268 },
269 };
270
271 Ok(eigenlayer_contract_deployer::core::deploy_core_contracts(
272 http_endpoint,
273 owner_private_key,
274 owner_account,
275 core_config,
276 Some(address!("00000000219ab540356cBB839Cbe05303d7705Fa")),
277 Some(1_564_000),
278 )
279 .await
280 .unwrap())
281}