Skip to content

Commit f21cbb5

Browse files
authored
fix(cheatcodes): identify common proxies in state diffs (#11404)
* fix(cheatcodes): identify proxies in state diffs * dedup get_contract_name and get_contract_data * clippy
1 parent e3a122a commit f21cbb5

File tree

1 file changed

+23
-28
lines changed

1 file changed

+23
-28
lines changed

crates/cheatcodes/src/evm.rs

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,8 +1346,8 @@ fn get_recorded_state_diffs(ccx: &mut CheatsCtxt) -> BTreeMap<Address, AccountSt
13461346
let mut contract_names = HashMap::new();
13471347
let mut storage_layouts = HashMap::new();
13481348
for address in addresses_to_lookup {
1349-
if let Some(name) = get_contract_name(ccx, address) {
1350-
contract_names.insert(address, name);
1349+
if let Some((artifact_id, _)) = get_contract_data(ccx, address) {
1350+
contract_names.insert(address, artifact_id.identifier());
13511351
}
13521352

13531353
// Also get storage layout if available
@@ -1471,33 +1471,12 @@ fn get_recorded_state_diffs(ccx: &mut CheatsCtxt) -> BTreeMap<Address, AccountSt
14711471
state_diffs
14721472
}
14731473

1474-
/// Helper function to get the contract name from the deployed code.
1475-
fn get_contract_name(ccx: &mut CheatsCtxt, address: Address) -> Option<String> {
1476-
// Check if we have available artifacts to match against
1477-
let artifacts = ccx.state.config.available_artifacts.as_ref()?;
1478-
1479-
// Try to load the account and get its code
1480-
let account = ccx.ecx.journaled_state.load_account(address).ok()?;
1481-
let code = account.info.code.as_ref()?;
1482-
1483-
// Skip if code is empty
1484-
if code.is_empty() {
1485-
return None;
1486-
}
1487-
1488-
// Try to find the artifact by deployed code
1489-
let code_bytes = code.original_bytes();
1490-
if let Some((artifact_id, _)) = artifacts.find_by_deployed_code_exact(&code_bytes) {
1491-
return Some(artifact_id.identifier());
1492-
}
1474+
/// EIP-1967 implementation storage slot
1475+
const EIP1967_IMPL_SLOT: &str = "360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
14931476

1494-
// Fallback to fuzzy matching if exact match fails
1495-
if let Some((artifact_id, _)) = artifacts.find_by_deployed_code(&code_bytes) {
1496-
return Some(artifact_id.identifier());
1497-
}
1498-
1499-
None
1500-
}
1477+
/// EIP-1822 UUPS implementation storage slot: keccak256("PROXIABLE")
1478+
const EIP1822_PROXIABLE_SLOT: &str =
1479+
"c5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7";
15011480

15021481
/// Helper function to get the contract data from the deployed code at an address.
15031482
fn get_contract_data<'a>(
@@ -1518,6 +1497,22 @@ fn get_contract_data<'a>(
15181497

15191498
// Try to find the artifact by deployed code
15201499
let code_bytes = code.original_bytes();
1500+
// First check for proxy patterns
1501+
let hex_str = hex::encode(&code_bytes);
1502+
let find_by_suffix =
1503+
|suffix: &str| artifacts.iter().find(|(a, _)| a.identifier().ends_with(suffix));
1504+
// Simple proxy detection based on storage slot patterns
1505+
if hex_str.contains(EIP1967_IMPL_SLOT)
1506+
&& let Some(result) = find_by_suffix(":TransparentUpgradeableProxy")
1507+
{
1508+
return Some(result);
1509+
} else if hex_str.contains(EIP1822_PROXIABLE_SLOT)
1510+
&& let Some(result) = find_by_suffix(":UUPSUpgradeable")
1511+
{
1512+
return Some(result);
1513+
}
1514+
1515+
// Try exact match
15211516
if let Some(result) = artifacts.find_by_deployed_code_exact(&code_bytes) {
15221517
return Some(result);
15231518
}

0 commit comments

Comments
 (0)