Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: use provider in contract error instead of network choice string #2385

Merged
merged 4 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
# ** Dependencies maintained by Ethereum Foundation **
"eth-abi>=5.1.0,<6",
"eth-account>=0.13.4,<0.14",
"eth-tester>=0.12.0b2,<0.13", # Peer: stricter pin needed for [tester].
"eth-typing>=5.0.1,<6",
"eth-utils>=5.1.0,<6",
"hexbytes>=1.2.1,<2",
Expand Down
6 changes: 1 addition & 5 deletions src/ape/contracts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,7 @@ def decode_input(self, calldata: bytes) -> tuple[str, dict[str, Any]]:

def _validate_is_contract(self):
if not self.contract.is_contract:
raise ContractNotFoundError(
self.contract.address,
self.provider.network.explorer is not None,
self.provider.network_choice,
)
raise ContractNotFoundError(self.contract.address, provider=self.provider)


class ContractCallHandler(ContractMethodHandler):
Expand Down
36 changes: 23 additions & 13 deletions src/ape/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from ethpm_types.contract_type import ContractType

from ape.api.networks import NetworkAPI
from ape.api.providers import SubprocessProvider
from ape.api.providers import ProviderAPI, SubprocessProvider
from ape.api.trace import TraceAPI
from ape.api.transactions import ReceiptAPI, TransactionAPI
from ape.managers.project import ProjectManager
Expand Down Expand Up @@ -590,29 +590,39 @@ class ContractNotFoundError(ChainError):
Raised when a contract is not found at an address.
"""

# TODO: In 0.9, pass in provider object directly (instead of network choice + name)
def __init__(self, address: "AddressType", has_explorer: bool, network_choice: str):
def __init__(self, address: "AddressType", provider: Optional["ProviderAPI"] = None):
try:
msg = self._create_message(address, provider=provider)
except Exception as err:
# Don't let errors occurring within exception handling to
# ruin the exception completely.
logger.error(f"Failed to create proper error message because of: {err}")
msg = f"Failed to get contract type for address '{address}'."

super().__init__(msg)

@classmethod
def _create_message(
cls, address: "AddressType", provider: Optional["ProviderAPI"] = None
) -> str:
msg = f"Failed to get contract type for address '{address}'."
if not provider:
return msg

# NOTE: Network name is optional to avoid breaking change.
choice_parts = network_choice.split(":")
if len(choice_parts) > 1:
network_name = network_choice.split(":")[1]
else:
network_name = network_choice
network_name = provider.network_choice.split(":")[1]

if has_explorer:
msg += " Contract may need verification."
if provider.network.explorer:
msg += " Contract may need verification (if relying on an explorer)."
elif network_name != "local":
# Only bother mentioning explorer plugins if we are not the local network.
msg += (
f" Current network '{network_choice}' has no associated "
f" Current network '{provider.network_choice}' has no associated "
"explorer plugin. Try installing an explorer plugin using "
f"{click.style(text='ape plugins install etherscan', fg='green')}, "
"or using a network with explorer support."
)

super().__init__(msg)
return msg


class UnknownSnapshotError(ChainError):
Expand Down
10 changes: 2 additions & 8 deletions src/ape/managers/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,9 +972,7 @@ def __getitem__(self, address: AddressType) -> ContractType:
contract_type = self.get(address)
if not contract_type:
# Create error message from custom exception cls.
err = ContractNotFoundError(
address, self.provider.network.explorer is not None, self.provider.network_choice
)
err = ContractNotFoundError(address, provider=self.provider)
# Must raise KeyError.
raise KeyError(str(err))

Expand Down Expand Up @@ -1242,11 +1240,7 @@ def instance_at(
)

if not contract_type:
raise ContractNotFoundError(
contract_address,
self.provider.network.explorer is not None,
self.provider.network_choice,
)
raise ContractNotFoundError(contract_address, provider=self.provider)

elif not isinstance(contract_type, ContractType):
raise TypeError(
Expand Down
5 changes: 3 additions & 2 deletions src/ape_ethereum/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -1593,8 +1593,9 @@ def ots_get_contract_creator(self, address: "AddressType") -> Optional[dict]:

result = self.make_request("ots_getContractCreator", [address])
if result is None:
# NOTE: Skip the explorer part of the error message via `has_explorer=True`.
raise ContractNotFoundError(address, True, self.network_choice)
# Don't pass provider so the error message is simplifer in this case
# (avoids mentioning explorer plugins).
raise ContractNotFoundError(address)

return result

Expand Down
3 changes: 3 additions & 0 deletions tests/functional/test_contract_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
ProjectError,
)
from ape_ethereum.ecosystem import ProxyType
from tests.conftest import explorer_test


def test_deploy(
Expand Down Expand Up @@ -166,6 +167,7 @@ def test_at(vyper_contract_instance, vyper_contract_container):
assert instance == vyper_contract_instance


@explorer_test
def test_at_fetch_from_explorer_false(
project_with_contract, mock_explorer, eth_tester_provider, owner
):
Expand All @@ -188,3 +190,4 @@ def test_at_fetch_from_explorer_false(

# Clean up test.
eth_tester_provider.network.explorer = None
assert eth_tester_provider.network.explorer is None
21 changes: 14 additions & 7 deletions tests/functional/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
handle_ape_exception,
)
from ape.types.trace import SourceTraceback
from ape.utils.misc import LOCAL_NETWORK_NAME, ZERO_ADDRESS
from ape.utils.misc import ZERO_ADDRESS
from ape_ethereum.transactions import DynamicFeeTransaction, Receipt


Expand Down Expand Up @@ -230,20 +230,27 @@ def revert_type(self) -> Optional[str]:


class TestContractNotFoundError:
def test_local_network(self):
def test_local_network(self, eth_tester_provider):
"""
Testing we are NOT mentioning explorer plugins
for the local-network, as 99.9% of the time it is
confusing.
"""
err = ContractNotFoundError(ZERO_ADDRESS, False, f"ethereum:{LOCAL_NETWORK_NAME}:test")
assert str(err) == f"Failed to get contract type for address '{ZERO_ADDRESS}'."
eth_tester_provider.network.explorer = None # Ensure no explorer is set.
err = ContractNotFoundError(ZERO_ADDRESS, provider=eth_tester_provider)
actual = f"{err}"
expected = f"Failed to get contract type for address '{ZERO_ADDRESS}'."
assert actual == expected

def test_fork_network(self):
err = ContractNotFoundError(ZERO_ADDRESS, False, "ethereum:sepolia-fork:test")
def test_fork_network(self, mocker, mock_sepolia):
provider = mocker.MagicMock()
provider.network = mock_sepolia
mock_sepolia.explorer = None
provider.network_choice = "ethereum:sepolia:node"
err = ContractNotFoundError(ZERO_ADDRESS, provider=provider)
assert str(err) == (
f"Failed to get contract type for address '{ZERO_ADDRESS}'. "
"Current network 'ethereum:sepolia-fork:test' has no associated explorer plugin. "
"Current network 'ethereum:sepolia:node' has no associated explorer plugin. "
"Try installing an explorer plugin using \x1b[32mape plugins install etherscan"
"\x1b[0m, or using a network with explorer support."
)
Expand Down
Loading