Skip to content

Commit

Permalink
fix: use deep copy
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Dec 12, 2024
1 parent f21a636 commit 81fad15
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 17 deletions.
9 changes: 3 additions & 6 deletions src/ape/managers/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,6 @@ def cache_deployment(self, contract_instance: ContractInstance):
contract_instance (:class:`~ape.contracts.base.ContractInstance`): The contract
to cache.
"""

address = contract_instance.address
contract_type = contract_instance.contract_type # may be a proxy

Expand All @@ -809,20 +808,18 @@ def cache_deployment(self, contract_instance: ContractInstance):
self.cache_proxy_info(address, proxy_info)
if implementation_contract := self.get(proxy_info.target):
# Include proxy ABIs but ignore fallback/ctor etc.
abis = list(implementation_contract.abi)
proxy_abis = [
abi for abi in contract_type.abi if abi.type in ("error", "event", "function")
]
abis.extend(proxy_abis)

# Include "hidden" ABIs, such as Safe's `masterCopy()`.
if proxy_info.abi and proxy_info.abi.signature not in [
abi.signature for abi in contract_type.abi
]:
abis.append(proxy_info.abi)
proxy_abis.append(proxy_info.abi)

updated_proxy_contract = implementation_contract.model_copy()
updated_proxy_contract.abi = abis
updated_proxy_contract = implementation_contract.model_copy(deep=True)
updated_proxy_contract.abi.extend(proxy_abis)
self._cache_contract_type(address, updated_proxy_contract)

# Use this contract type in the user's contract instance.
Expand Down
24 changes: 19 additions & 5 deletions tests/functional/test_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,16 +286,30 @@ def test_deploy_and_not_publish(owner, contract_container, dummy_live_network, m
def test_deploy_proxy(owner, vyper_contract_instance, proxy_contract_container, chain):
target = vyper_contract_instance.address
proxy = owner.deploy(proxy_contract_container, target)

# Ensure we can call both proxy and target methods on it.
assert proxy.implementation # No attr err
assert proxy.myNumber # No attr err

# Ensure was properly cached.
assert proxy.address in chain.contracts._local_contract_types
assert proxy.address in chain.contracts._local_proxies

actual = chain.contracts._local_proxies[proxy.address]
assert actual.target == target
assert actual.type == ProxyType.Delegate
# Show the cached proxy info is correct.
proxy_info = chain.contracts._local_proxies[proxy.address]
assert proxy_info.target == target
assert proxy_info.type == ProxyType.Delegate
assert proxy_info.abi.name == "implementation"

# Show we get the implementation contract type using the proxy address
implementation = chain.contracts.instance_at(proxy.address)
assert implementation.contract_type == vyper_contract_instance.contract_type
re_contract = chain.contracts.instance_at(proxy.address)
assert re_contract.contract_type == proxy.contract_type

# Show proxy methods are not available on target alone.
target = chain.contracts.instance_at(proxy_info.target)
assert target.myNumber # No attr err
with pytest.raises(AttributeError):
_ = target.implementation


def test_deploy_instance(owner, vyper_contract_instance):
Expand Down
25 changes: 19 additions & 6 deletions tests/functional/test_contract_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,33 @@ def test_deployments(owner, eth_tester_provider, vyper_contract_container):


def test_deploy_proxy(
owner, project, vyper_contract_instance, proxy_contract_container, chain, eth_tester_provider
owner, vyper_contract_instance, proxy_contract_container, chain, eth_tester_provider
):
target = vyper_contract_instance.address
proxy = proxy_contract_container.deploy(target, sender=owner)

# Ensure we can call both proxy and target methods on it.
assert proxy.implementation # No attr err
assert proxy.myNumber # No attr err

# Ensure caching works.
assert proxy.address in chain.contracts._local_contract_types
assert proxy.address in chain.contracts._local_proxies

actual = chain.contracts._local_proxies[proxy.address]
assert actual.target == target
assert actual.type == ProxyType.Delegate
# Show the cached proxy info is correct.
proxy_info = chain.contracts._local_proxies[proxy.address]
assert proxy_info.target == target
assert proxy_info.type == ProxyType.Delegate

# Show we get the implementation contract type using the proxy address
implementation = chain.contracts.instance_at(proxy.address)
assert implementation.contract_type == vyper_contract_instance.contract_type
re_contract = chain.contracts.instance_at(proxy.address)
assert re_contract.contract_type == proxy.contract_type

# Show proxy methods are not available on target alone.
target = chain.contracts.instance_at(proxy_info.target)
assert target.myNumber # No attr err
with pytest.raises(AttributeError):
_ = target.implementation


def test_source_path_in_project(project_with_contract):
Expand Down

0 comments on commit 81fad15

Please sign in to comment.