Skip to content

Commit

Permalink
Supporting EIP1967 direct and beacon proxies
Browse files Browse the repository at this point in the history
  • Loading branch information
naps62 committed Feb 3, 2025
1 parent f9f260d commit 548ae53
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 14 deletions.
77 changes: 76 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
alloy = { version = "0.11.0", features = ["providers", "reqwest-rustls-tls"] }
rstest = "0.24.0"
thiserror = "2.0.11"

[dev-dependencies]
Expand Down
8 changes: 2 additions & 6 deletions src/eip1167.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use alloy::{
hex,
primitives::{bytes, Address, Bytes},
};
use alloy::primitives::{bytes, Address, Bytes};

const EIP1167_PREFIX: Bytes = bytes!("363d3d373d3d3d363d");
const EIP1167_SUFFIX: Bytes = bytes!("57fd5bf3");
Expand All @@ -23,13 +20,12 @@ pub(crate) fn detect_eip1167_minimal_proxy(code: &Bytes) -> Option<Address> {
let address_pos = EIP1167_PREFIX.len() + 1;
let suffix = &code[address_pos + address_len + EIP1167_SUFFIX_OFFSET_FROM_ADDRESS_END..];

dbg!(&hex::encode(suffix));
if !suffix.starts_with(&EIP1167_SUFFIX) {
return None;
}

let address_hex = &code[address_pos..address_pos + address_len];
let address = Address::from_slice(address_hex);
let address = Address::left_padding_from(address_hex);

Some(address)
}
Expand Down
56 changes: 56 additions & 0 deletions src/eip1967.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use alloy::{
network::Network,
primitives::{b256, Address, Bytes, B256, U256},
providers::Provider,
};

use crate::{error::DetectProxyResult, ProxyType};

// bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
const EIP1967_LOGIC_SLOT: B256 =
b256!("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc");
const EIP1967_BEACON_SLOT: B256 =
b256!("0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50");

pub(crate) async fn detect_eip1967_direct_proxy<N, P: Provider<N>>(
address: Address,
provider: P,
) -> DetectProxyResult<Option<ProxyType>>
where
N: Network,
{
if let Ok(Some(addr)) = storage_slot_as_address(&provider, address, EIP1967_LOGIC_SLOT).await {
return Ok(Some(ProxyType::Eip1967Direct(addr)));
}

if let Ok(Some(addr)) = storage_slot_as_address(&provider, address, EIP1967_BEACON_SLOT).await {
return Ok(Some(ProxyType::Eip1967Beacon(addr)));
}

Ok(None)
}

async fn storage_slot_as_address<N, P: Provider<N>>(
provider: P,
address: Address,
slot: B256,
) -> DetectProxyResult<Option<Address>>
where
N: Network,
{
let slot = provider
.get_storage_at(address, slot.into())
.latest()
.await?;

if !slot.is_zero() {
return Ok(Some(u256_to_address(slot)));
}

Ok(None)
}

fn u256_to_address(u256: U256) -> Address {
let bytes: Bytes = u256.to_be_bytes::<32>().into();
Address::from_slice(&bytes[12..])
}
26 changes: 19 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod eip1167;
mod eip1967;
mod error;

use alloy::{network::Network, primitives::Address, providers::Provider};
Expand All @@ -7,6 +8,8 @@ use error::DetectProxyResult;
#[derive(Debug, PartialEq)]
pub enum ProxyType {
Eip1167(Address),
Eip1967Direct(Address),
Eip1967Beacon(Address),
}

pub async fn detect_proxy<N, P: Provider<N>>(
Expand All @@ -22,6 +25,10 @@ where
return Ok(Some(ProxyType::Eip1167(address)));
}

if let Some(proxy_type) = eip1967::detect_eip1967_direct_proxy(address, provider).await? {
return Ok(Some(proxy_type));
}

Ok(None)
}

Expand All @@ -30,23 +37,28 @@ mod tests {
use super::*;
use alloy::{primitives::address, providers::ProviderBuilder, transports::http::reqwest::Url};
use lazy_static::lazy_static;
use rstest::*;

const MAINNET_EIP1167_PROXY: Address = address!("0x6d5d9b6ec51c15f45bfa4c460502403351d5b999");
const MAINNET_EIP1167_IMPL: Address = address!("0x210fF9Ced719E9bf2444DbC3670BAC99342126fA");
lazy_static! {
static ref MAINNET_RPC: Url = Url::parse(
&std::env::var("ETH_MAINNET_RPC").unwrap_or("https://eth.rpc.blxrbdn.com".to_string())
)
.unwrap();
}

#[rstest]
#[case::eip1167(address!("0x6d5d9b6ec51c15f45bfa4c460502403351d5b999"), ProxyType::Eip1167(address!("0x210fF9Ced719E9bf2444DbC3670BAC99342126fA")))]
#[case::eip1167_vanity(address!("0xa81043fd06D57D140f6ad8C2913DbE87fdecDd5F"), ProxyType::Eip1167(address!("0x0000000010fd301be3200e67978e3cc67c962f48")))]
#[case::eip1967_direct(address!("0xA7AeFeaD2F25972D80516628417ac46b3F2604Af"), ProxyType::Eip1967Direct(address!("0x4bd844f72a8edd323056130a86fc624d0dbcf5b0")))]
#[case::eip1967_direct(address!("0x8260b9eC6d472a34AD081297794d7Cc00181360a"), ProxyType::Eip1967Direct(address!("0xe4e4003afe3765aca8149a82fc064c0b125b9e5a")))]
#[case::eip1967_beacon(address!("0xDd4e2eb37268B047f55fC5cAf22837F9EC08A881"), ProxyType::Eip1967Beacon(address!("0xb3e0edda8c2aeabfdece18ad7ac1ea86eb7d583b")))]
#[case::eip1967_beacon(address!("0x114f1388fAB456c4bA31B1850b244Eedcd024136"), ProxyType::Eip1967Beacon(address!("0xbe86f647b167567525ccaafcd6f881f1ee558216")))]
#[tokio::test]
async fn mainnet_eip1167() {
async fn mainnet(#[case] proxy: Address, #[case] impl_: ProxyType) {
let provider = ProviderBuilder::new().on_http(MAINNET_RPC.clone());
let result = detect_proxy(MAINNET_EIP1167_PROXY, &provider)
.await
.unwrap();

assert_eq!(result, Some(ProxyType::Eip1167(MAINNET_EIP1167_IMPL)));
let result = detect_proxy(proxy, &provider).await.unwrap();

assert_eq!(result, Some(impl_));
}
}

0 comments on commit 548ae53

Please sign in to comment.