Skip to content

Commit b693334

Browse files
committed
refactor(Ethereum): improve efficiency of SafeProxy detection heuristic
1 parent e0b43f2 commit b693334

File tree

1 file changed

+21
-10
lines changed

1 file changed

+21
-10
lines changed

src/ape_ethereum/ecosystem.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
CustomError,
3737
DecodingError,
3838
SignatureError,
39+
TransactionError,
3940
)
4041
from ape.logging import logger
4142
from ape.managers.config import merge_configs
@@ -531,18 +532,28 @@ def str_to_slot(text):
531532

532533
return ProxyInfo(type=_type, target=target, abi=IMPLEMENTATION_ABI)
533534

534-
# safe >=1.1.0 provides `masterCopy()`, which is also stored in slot 0
535-
# call it and check that target matches
536-
try:
537-
singleton = ContractCall(MASTER_COPY_ABI, address)(skip_trace=True)
535+
# safe >=1.1.0 provides `masterCopy()` (0xa619486e), which is also stored in slot 0
536+
if re.match(r".*a619486e.*", code): # NOTE: Such a short sequence can have false positives
538537
slot_0 = self.provider.get_storage(address, 0)
539-
target = self.conversion_manager.convert(slot_0[-20:], AddressType)
540-
# NOTE: `target` is set in initialized proxies
541-
if target != ZERO_ADDRESS and target == singleton:
542-
return ProxyInfo(type=ProxyType.GnosisSafe, target=target, abi=MASTER_COPY_ABI)
538+
# Slot value is "address-like" heuristic (all contract addresses have >12 nonzero bytes)
539+
# NOTE: Farming an address with 8 leading zeros is pretty improbable
540+
if all(b == 0 for b in slot_0[:-20]) and sum(1 for b in slot_0[-20:] if b > 0) >= 12:
541+
# Slot is "address-like", so convert it
542+
target = self.conversion_manager.convert(slot_0[-20:], AddressType)
543543

544-
except ApeException:
545-
pass
544+
try:
545+
# call `masterCopy()` and check that target matches return value
546+
singleton = ContractCall(MASTER_COPY_ABI, address)(skip_trace=True)
547+
548+
except TransactionError:
549+
pass
550+
551+
else:
552+
# NOTE: `target` is set in initialized proxies like GnosisSafe
553+
if target == singleton:
554+
return ProxyInfo(
555+
type=ProxyType.GnosisSafe, target=target, abi=MASTER_COPY_ABI
556+
)
546557

547558
# eip-897 delegate proxy, read `proxyType()` and `implementation()`
548559
# perf: only make a call when a proxyType() selector is mentioned in the code

0 commit comments

Comments
 (0)