Skip to content

Commit

Permalink
fix: allow Gnosis Safe style proxies to work with earlier deployments (
Browse files Browse the repository at this point in the history
…#1178)

* fix: allow Gnosis Safe style proxies to work with earlier deployments

Prior to v1.1.0, `masterCopy` was not available as an external method.
This means that our proxy detection would not be able to detect it as
a Gnosis Safe-style proxy. Additionally, once deployed, this style of
proxy is immutable, so even if the Safe itself is upgraded to a newer
version, this method still would not be available to be called.

NOTE: This slightly modifies the proxy info's target to be obtained
      dynamically from retreiving the storage for `masterCopy` directly.

* fix: bug when looking at uninitialized proxies

* refactor: cleanup a little bit
  • Loading branch information
fubuloubu authored Dec 13, 2022
1 parent 8f70917 commit b9d0615
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/ape_ethereum/ecosystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ape.utils import (
DEFAULT_LOCAL_TRANSACTION_ACCEPTANCE_TIMEOUT,
DEFAULT_TRANSACTION_ACCEPTANCE_TIMEOUT,
ZERO_ADDRESS,
LogInputABICollection,
Struct,
StructParser,
Expand Down Expand Up @@ -216,19 +217,21 @@ def str_to_slot(text):

return ProxyInfo(type=type, target=target)

# gnosis safe stores implementation in slot 0, read `masterCopy()` to be sure
# gnosis safe stores implementation in slot 0, read `NAME()` to be sure
abi = MethodABI(
type="function",
name="masterCopy",
name="NAME",
stateMutability="view",
outputs=[ABIType(type="address")],
outputs=[ABIType(type="string")],
)
try:
master_copy = ContractCall(abi, address)()
storage = self.provider.get_storage_at(address, 0)
slot_0 = self.conversion_manager.convert(storage[-20:].hex(), AddressType)
if master_copy == slot_0:
return ProxyInfo(type=ProxyType.GnosisSafe, target=master_copy)
name = ContractCall(abi, address)()
raw_target = self.provider.get_storage_at(address, 0)[-20:].hex()
target = self.conversion_manager.convert(raw_target, AddressType)
# NOTE: `target` is set in initialized proxies
if name in ("Gnosis Safe", "Default Callback Handler") and target != ZERO_ADDRESS:
return ProxyInfo(type=ProxyType.GnosisSafe, target=target)

except (DecodingError, TransactionError):
pass

Expand All @@ -252,7 +255,7 @@ def str_to_slot(text):

target = ContractCall(implementation_abi, address)()
# avoid recursion
if target != "0x0000000000000000000000000000000000000000":
if target != ZERO_ADDRESS:
return ProxyInfo(type=ProxyType.Delegate, target=target)

except (DecodingError, TransactionError, ValueError):
Expand Down

0 comments on commit b9d0615

Please sign in to comment.