Skip to content

Commit

Permalink
fix: issue where using Contract(abi= did not cache the ABI (#2177)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Jul 12, 2024
1 parent e1c9dcf commit 60969be
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/ape/contracts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1286,7 +1286,7 @@ def __getattr__(self, attr_name: str) -> Any:
}:
# Didn't find anything that matches
# NOTE: `__getattr__` *must* raise `AttributeError`
name = self.contract_type.name or ContractType.__name__
name = self.contract_type.name or ContractInstance.__name__
raise ApeAttributeError(f"'{name}' has no attribute '{attr_name}'.")

elif (
Expand Down
13 changes: 9 additions & 4 deletions src/ape/managers/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,8 @@ def __setitem__(self, address: AddressType, contract_type: ContractType):
self._cache_contract_type(address, contract_type)

# NOTE: The txn_hash is not included when caching this way.
self._cache_deployment(address, contract_type)
if contract_type.name:
self._cache_deployment(address, contract_type)

def __delitem__(self, address: AddressType):
"""
Expand Down Expand Up @@ -808,7 +809,8 @@ def cache_deployment(self, contract_instance: ContractInstance):

txn_hash = contract_instance.txn_hash
self._cache_contract_type(address, contract_type)
self._cache_deployment(address, contract_type, txn_hash)
if contract_type.name:
self._cache_deployment(address, contract_type, txn_hash)

def cache_proxy_info(self, address: AddressType, proxy_info: ProxyInfoAPI):
"""
Expand Down Expand Up @@ -957,7 +959,7 @@ def _cache_deployment(
self, address: AddressType, contract_type: ContractType, txn_hash: Optional[str] = None
):
deployments = self._deployments
contract_deployments = deployments.get(contract_type.name, [])
contract_deployments = deployments.get(contract_type.name or "", [])
new_deployment = {"address": address, "transaction_hash": txn_hash}
contract_deployments.append(new_deployment)
self._deployments = {**deployments, contract_type.name: contract_deployments}
Expand Down Expand Up @@ -1214,6 +1216,9 @@ def instance_at(
if isinstance(abi, list):
contract_type = ContractType(abi=abi)

# Ensure we cache the contract-types from ABI!
self[contract_address] = contract_type

else:
raise TypeError(
f"Invalid ABI type '{type(abi)}', expecting str, list[ABI] or a JSON file."
Expand Down Expand Up @@ -1394,7 +1399,7 @@ def _cache_contract_creation_to_disk(self, address: AddressType, creation: Contr

def _load_deployments_cache(self) -> dict:
return (
json.loads(self._deployments_mapping_cache.read_text())
json.loads(self._deployments_mapping_cache.read_text(encoding="utf8"))
if self._deployments_mapping_cache.is_file()
else {}
)
Expand Down
16 changes: 16 additions & 0 deletions tests/functional/test_contracts_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ def test_instance_at_contract_type_not_found(chain, eth_tester_provider):
chain.contracts.instance_at(new_address)


def test_instance_at_use_abi(chain, solidity_fallback_contract, owner):
new_instance = owner.deploy(solidity_fallback_contract.contract_type)
del chain.contracts[new_instance.address]
with pytest.raises(ContractNotFoundError):
_ = chain.contracts.instance_at(new_instance.address)

# Now, use only ABI and ensure it works and caches!
abi = solidity_fallback_contract.contract_type.abi
instance = chain.contracts.instance_at(new_instance.address, abi=abi)
assert instance.contract_type.abi

# `abi=` not needed this time.
instance2 = chain.contracts.instance_at(new_instance.address)
assert instance2.contract_type.abi == instance.contract_type.abi


def test_cache_deployment_live_network(
chain,
vyper_contract_instance,
Expand Down

0 comments on commit 60969be

Please sign in to comment.