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

feat: enrich_error() implementation [APE-812] #93

Merged
merged 6 commits into from
Apr 13, 2023
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
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ repos:
- id: isort

- repo: https://github.com/psf/black
rev: 22.12.0
rev: 23.3.0
hooks:
- id: black
name: black

- repo: https://github.com/pycqa/flake8
rev: 5.0.4
rev: 6.0.0
hooks:
- id: flake8

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ A pull request represents the start of a discussion, and doesn't necessarily nee
If you are opening a work-in-progress pull request to verify that it passes CI tests, please consider
[marking it as a draft](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests).

Join the Ethereum Python [Discord](https://discord.gg/PcEJ54yX) if you have any questions.
Join the ApeWorX [Discord](https://discord.gg/apeworx) if you have any questions.

## Testing

Expand Down
38 changes: 35 additions & 3 deletions ape_solidity/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
import solcx # type: ignore
from ape.api import CompilerAPI, PluginConfig
from ape.contracts import ContractInstance
from ape.exceptions import CompilerError
from ape.exceptions import CompilerError, ContractLogicError
from ape.logging import logger
from ape.types import AddressType, ContractType
from ape.utils import cached_property, get_relative_path
from ethpm_types import PackageManifest
from eth_utils import is_0x_prefixed
from ethpm_types import HexBytes, PackageManifest
from requests.exceptions import ConnectionError
from semantic_version import NpmSpec, Version # type: ignore
from solcx.exceptions import SolcError # type: ignore
Expand Down Expand Up @@ -259,7 +260,6 @@ def _add_dependencies(
def get_compiler_settings(
self, contract_filepaths: List[Path], base_path: Optional[Path] = None
) -> Dict[Version, Dict]:

# Currently needed because of a bug in Ape core 0.5.5.
only_files = []
for path in contract_filepaths:
Expand Down Expand Up @@ -659,3 +659,35 @@ def _get_best_version(self, path: Path, source_by_pragma_spec: Dict) -> Version:
if pragma_spec
else max(self.installed_versions)
)

def enrich_error(self, err: ContractLogicError) -> ContractLogicError:
if not is_0x_prefixed(err.revert_message):
return err

# Check for ErrorABI.
bytes_message = HexBytes(err.revert_message)
selector = bytes_message[:4]
input_data = bytes_message[4:]
address = err.contract_address or getattr(err.txn, "receiver", None)
if not address:
return err

if not self.network_manager.active_provider:
# Connection required.
return err

contract = self.chain_manager.contracts.instance_at(address)
if not contract:
return err

if selector not in contract.contract_type.errors:
# Not an ErrorABI selector.
return err

ecosystem = self.provider.network.ecosystem
abi = contract.contract_type.errors[selector]
inputs = ecosystem.decode_calldata(abi, input_data)
error_class = contract.get_error_by_signature(abi.signature)
return error_class(
abi, inputs, txn=err.txn, trace=err.trace, contract_address=err.contract_address
)
10 changes: 5 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
"hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer
],
"lint": [
"black>=22.12.0", # auto-formatter and linter
"mypy>=0.991", # Static type analyzer
"black>=23.3.0,<24", # Auto-formatter and linter
"mypy>=0.991,<1", # Static type analyzer
"types-requests", # Needed due to mypy typeshed
"types-setuptools", # Needed due to mypy typeshed
"flake8>=5.0.4", # Style linter
"isort>=5.10.1", # Import sorting linter
"flake8>=6.0.0,<7", # Style linter
"isort>=5.10.1,<6", # Import sorting linter
"mdformat>=0.7.16", # Auto-formatter for markdown
"mdformat-gfm>=0.3.5", # Needed for formatting GitHub-flavored markdown
"mdformat-frontmatter>=0.4.1", # Needed for frontmatters-style headers in issue templates
Expand Down Expand Up @@ -65,7 +65,7 @@
include_package_data=True,
install_requires=[
"py-solc-x>=1.1.0,<2",
"eth-ape>=0.6.4,<0.7",
"eth-ape>=0.6.8,<0.7",
"ethpm-types", # Use the version ape requires
"packaging", # Use the version ape requires
"requests",
Expand Down
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ def account():
return ape.accounts.test_accounts[0]


@pytest.fixture
def owner():
return ape.accounts.test_accounts[1]


@pytest.fixture
def not_owner():
return ape.accounts.test_accounts[2]


@pytest.fixture
def connection():
with ape.networks.ethereum.local.use_provider("test"):
Expand Down
16 changes: 16 additions & 0 deletions tests/contracts/HasError.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

error Unauthorized(address addr, uint256 counter);

contract HasError {
address payable owner = payable(msg.sender);

function withdraw() public {
if (msg.sender != owner)
revert Unauthorized(msg.sender, 123);

owner.transfer(address(this).balance);
}
// ...
}
11 changes: 11 additions & 0 deletions tests/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,14 @@ def test_add_library(project, account, compiler, connection):

# After deploying and adding the library, we can use contracts that need it.
assert project.C


def test_enrich_error(compiler, project, owner, not_owner, connection):
compiler.compile((project.contracts_folder / "HasError.sol",))

# Deploy so Ape know about contract type.
contract = owner.deploy(project.HasError)
with pytest.raises(contract.Unauthorized) as err:
contract.withdraw(sender=not_owner)

assert err.value.inputs == {"addr": not_owner.address, "counter": 123}