eigenlayer_contract_deployer/
helpers.rs

1use std::str::FromStr;
2
3use crate::bindings::{EmptyContract, ProxyAdmin, TransparentUpgradeableProxy};
4use alloy::{
5    network::EthereumWallet,
6    signers::local::PrivateKeySigner,
7    transports::{TransportErrorKind, http::reqwest::Url},
8};
9use alloy_primitives::{Address, Bytes, FixedBytes};
10use alloy_provider::{
11    PendingTransactionBuilder, PendingTransactionError, ProviderBuilder, RootProvider,
12};
13use color_eyre::eyre::eyre;
14use tracing::error;
15
16/// Helper function to deploy an empty proxy
17///
18/// # Errors
19/// Returns an error if the deployment fails or if there are issues with the transaction receipt.
20pub async fn deploy_empty_proxy(
21    wallet: &RootProvider,
22    proxy_admin: Address,
23) -> color_eyre::eyre::Result<Address> {
24    let data = Bytes::new();
25
26    let empty_contract = EmptyContract::deploy(wallet).await?;
27    let &empty_contract_addr = empty_contract.address();
28
29    let proxy =
30        TransparentUpgradeableProxy::deploy(wallet, empty_contract_addr, proxy_admin, data).await?;
31
32    Ok(*proxy.address())
33}
34
35/// Helper function to upgrade a proxy with an implementation
36///
37/// # Errors
38/// Returns an error if the upgrade fails or if there are issues with the transaction receipt.
39pub async fn upgrade_proxy(
40    wallet: &RootProvider,
41    proxy_admin_addr: Address,
42    proxy_addr: Address,
43    implementation_addr: Address,
44    data: Bytes,
45) -> color_eyre::eyre::Result<()> {
46    let proxy_admin = ProxyAdmin::new(proxy_admin_addr, wallet.clone());
47
48    let receipt = if data.is_empty() {
49        let call = proxy_admin.upgrade(proxy_addr, implementation_addr);
50        get_receipt(call).await?
51    } else {
52        let call = proxy_admin.upgradeAndCall(proxy_addr, implementation_addr, data);
53        get_receipt(call).await?
54    };
55
56    if !receipt.status() {
57        return Err(eyre!("Failed to upgrade proxy"));
58    }
59
60    Ok(())
61}
62
63// use crate::error::Error;
64// use crate::state::{AnvilState, get_default_state_json};
65use alloy_contract::{CallBuilder, CallDecoder};
66use alloy_provider::Provider;
67use alloy_provider::network::Ethereum;
68use alloy_rpc_types_eth::TransactionReceipt;
69// use blueprint_core::{error, info};
70// use std::fs;
71// use tempfile::TempDir;
72// use testcontainers::{
73//     ContainerAsync, GenericImage, ImageExt,
74//     core::{ExecCommand, IntoContainerPort, WaitFor},
75//     runners::AsyncRunner,
76// };
77// use tokio::io::AsyncBufReadExt;
78
79#[allow(clippy::missing_errors_doc)]
80pub async fn get_receipt<P, D>(
81    call: CallBuilder<P, D, Ethereum>,
82) -> Result<TransactionReceipt, color_eyre::eyre::Error>
83where
84    P: Provider<Ethereum>,
85    D: CallDecoder,
86{
87    let pending_tx = match call.send().await {
88        Ok(tx) => tx,
89        Err(e) => {
90            error!("Failed to send transaction: {:?}", e);
91            return Err(e.into());
92        }
93    };
94
95    let receipt = match pending_tx.get_receipt().await {
96        Ok(receipt) => receipt,
97        Err(e) => {
98            error!("Failed to get transaction receipt: {:?}", e);
99            return Err(e.into());
100        }
101    };
102
103    Ok(receipt)
104}
105
106#[allow(clippy::type_complexity)]
107/// Get the provider for an http endpoint with the [`Wallet`](EthereumWallet) for the specified private key
108///
109/// # Returns
110/// - [`RootProvider`] - The provider
111///
112/// # Panics
113/// - If the provided http endpoint is not a valid URL
114#[must_use]
115pub fn get_provider_from_signer(key: &str, rpc_url: &str) -> RootProvider {
116    let signer = PrivateKeySigner::from_str(key).expect("wrong key ");
117    let wallet = EthereumWallet::from(signer);
118    let url = Url::parse(rpc_url).expect("Wrong rpc url");
119    ProviderBuilder::new()
120        .wallet(wallet.clone())
121        .connect_http(url)
122        .root()
123        .clone()
124}
125
126/// Wait for a transaction to finish and return its receipt.
127///
128/// # Arguments
129///
130/// `rpc_url` - The RPC URL.
131/// `tx_hash` - The hash of the transaction.
132///
133/// # Returns
134///
135/// A [`TransportResult`] containing the transaction hash.
136#[allow(clippy::missing_errors_doc)]
137pub async fn wait_transaction(
138    rpc_url: &str,
139    tx_hash: FixedBytes<32>,
140) -> Result<TransactionReceipt, PendingTransactionError> {
141    let url = Url::parse(rpc_url).map_err(|_| TransportErrorKind::custom_str("Invalid RPC URL"))?;
142    let root_provider = ProviderBuilder::new()
143        .disable_recommended_fillers()
144        .connect_http(url);
145    let pending_tx = PendingTransactionBuilder::new(root_provider, tx_hash);
146    pending_tx.get_receipt().await
147}