diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f189388..4852e8b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 + rev: v4.4.0 hooks: - id: check-yaml @@ -10,21 +10,27 @@ repos: - id: isort - repo: https://github.com/psf/black - rev: 23.3.0 + rev: 23.9.1 hooks: - id: black name: black - repo: https://github.com/pycqa/flake8 - rev: 6.0.0 + rev: 6.1.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.991 + rev: v1.5.1 hooks: - id: mypy additional_dependencies: [types-setuptools, pydantic] +- repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 + hooks: + - id: mdformat + additional_dependencies: [mdformat-gfm, mdformat-frontmatter] + default_language_version: python: python3.8 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 59de022..95cf9ad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,4 +49,4 @@ 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. diff --git a/ape_arbitrum/ecosystem.py b/ape_arbitrum/ecosystem.py index 84d6b6e..6e8bb62 100644 --- a/ape_arbitrum/ecosystem.py +++ b/ape_arbitrum/ecosystem.py @@ -26,6 +26,10 @@ } INTERNAL_TRANSACTION_TYPE = 106 +# NOTE: Use a hard-coded gas limit for testing +# because the block gasLimit is extremely high in Arbitrum networks. +LOCAL_GAS_LIMIT = 30_000_000 + class InternalTransaction(StaticFeeTransaction): type: int = Field(INTERNAL_TRANSACTION_TYPE, exclude=True) @@ -100,10 +104,11 @@ def _create_network_config( def _create_local_config(default_provider: Optional[str] = None, **kwargs) -> NetworkConfig: return _create_network_config( - required_confirmations=0, + block_time=0, default_provider=default_provider, + gas_limit=LOCAL_GAS_LIMIT, + required_confirmations=0, transaction_acceptance_timeout=DEFAULT_LOCAL_TRANSACTION_ACCEPTANCE_TIMEOUT, - gas_limit="max", **kwargs, ) @@ -219,8 +224,12 @@ def decode_receipt(self, data: dict) -> ReceiptAPI: elif "input" in data and isinstance(data["input"], str): data["input"] = HexBytes(data["input"]) + block_number = data.get("block_number") or data.get("blockNumber") + if block_number is None: + raise ValueError("Block number cannot be None") + return ArbitrumReceipt( - block_number=data.get("block_number") or data.get("blockNumber"), + block_number=block_number, contract_address=data.get("contract_address") or data.get("contractAddress"), gas_limit=data.get("gas", data.get("gas_limit", data.get("gasLimit"))) or 0, gas_price=data.get("gas_price", data.get("gasPrice")) or 0, diff --git a/setup.py b/setup.py index 0e38e82..35b4288 100644 --- a/setup.py +++ b/setup.py @@ -11,12 +11,12 @@ "hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer ], "lint": [ - "black>=23.3.0,<24", # auto-formatter and linter - "mypy>=0.991,<1", # Static type analyzer - "flake8>=6.0.0,<7", # Style linter + "black>=23.9.1,<24", # auto-formatter and linter + "mypy>=1.5.1,<2", # Static type analyzer + "flake8>=6.1.0,<7", # Style linter "isort>=5.10.1,<6", # Import sorting linter "types-setuptools", # Needed due to mypy typeshed - "mdformat>=0.7.16", # Auto-formatter for markdown + "mdformat>=0.7.17", # 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 ], diff --git a/tests/conftest.py b/tests/conftest.py index ae5d637..5ad004f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,7 +25,7 @@ def arbitrum(networks): @pytest.fixture def eth_tester_provider(): if not ape.networks.active_provider or ape.networks.provider.name != "test": - with ape.networks.ethereum.local.use_provider("test") as provider: + with ape.networks.arbitrum.local.use_provider("test") as provider: yield provider else: yield ape.networks.provider diff --git a/tests/test_ecosystem.py b/tests/test_ecosystem.py index fad6167..6768ab7 100644 --- a/tests/test_ecosystem.py +++ b/tests/test_ecosystem.py @@ -2,25 +2,28 @@ from ape_ethereum.transactions import TransactionType from ethpm_types import HexBytes, MethodABI -from ape_arbitrum.ecosystem import INTERNAL_TRANSACTION_TYPE, ArbitrumReceipt +from ape_arbitrum.ecosystem import INTERNAL_TRANSACTION_TYPE, LOCAL_GAS_LIMIT, ArbitrumReceipt def test_gas_limit(arbitrum): - assert arbitrum.config.local.gas_limit == "max" + # NOTE: The reason we have a hard-coded gas limit is because + # the block gas limit in Arbitrum is extremely high. + assert arbitrum.config.local.gas_limit == LOCAL_GAS_LIMIT -@pytest.mark.parametrize("type", (0, "0x0")) -def test_create_transaction(arbitrum, type, eth_tester_provider): - tx = arbitrum.create_transaction(type=type) +# NOTE: None because we want to show the default is STATIC +@pytest.mark.parametrize("tx_type", (None, 0, "0x0")) +def test_create_transaction(arbitrum, tx_type, eth_tester_provider): + tx = arbitrum.create_transaction(type=tx_type) assert tx.type == TransactionType.STATIC.value - assert tx.gas_limit == eth_tester_provider.max_gas + assert tx.gas_limit == LOCAL_GAS_LIMIT @pytest.mark.parametrize( - "type_", + "tx_type", (TransactionType.STATIC.value, TransactionType.DYNAMIC.value, INTERNAL_TRANSACTION_TYPE), ) -def test_encode_transaction(type_, arbitrum, eth_tester_provider): +def test_encode_transaction(tx_type, arbitrum, eth_tester_provider): abi = MethodABI.parse_obj( { "type": "function", @@ -31,8 +34,8 @@ def test_encode_transaction(type_, arbitrum, eth_tester_provider): } ) address = "0x274b028b03A250cA03644E6c578D81f019eE1323" - actual = arbitrum.encode_transaction(address, abi, sender=address, type=type_) - assert actual.gas_limit == eth_tester_provider.max_gas + actual = arbitrum.encode_transaction(address, abi, sender=address, type=tx_type) + assert actual.gas_limit == LOCAL_GAS_LIMIT def test_internal_tx(arbitrum): diff --git a/tests/test_integration.py b/tests/test_integration.py new file mode 100644 index 0000000..58ce90d --- /dev/null +++ b/tests/test_integration.py @@ -0,0 +1,53 @@ +import pytest +from ape._cli import cli as ape_cli +from click.testing import CliRunner + +EXPECTED_OUTPUT = """ +arbitrum +├── mainnet +│ └── geth (default) +├── goerli +│ └── geth (default) +└── local (default) + └── test (default) +""".strip() + + +@pytest.fixture +def runner(): + return CliRunner() + + +@pytest.fixture +def cli(): + return ape_cli + + +def assert_rich_text(actual: str, expected: str): + """ + The output from `rich` causes a bunch of extra spaces to + appear at the end of each line. For easier testing, we remove those here. + Also, we ignore whether the expected line is at the end or in the middle + of the output to handle cases when the test-runner has additional plugins + installed. + """ + expected_lines = [ + x.replace("└", "").replace("├", "").replace("│", "").strip() + for x in expected.strip().split("\n") + ] + actual_lines = [ + x.replace("└", "").replace("├", "").replace("│", "").strip() + for x in actual.strip().split("\n") + ] + + for expected_line in expected_lines: + assert expected_line in actual_lines + + +def test_networks(runner, cli, arbitrum): + # Do this in case local env changed it. + arbitrum.mainnet.set_default_provider("geth") + arbitrum.goerli.set_default_provider("geth") + + result = runner.invoke(cli, ["networks", "list"]) + assert_rich_text(result.output, EXPECTED_OUTPUT) diff --git a/tests/test_provider.py b/tests/test_provider.py index 573e68d..366c683 100644 --- a/tests/test_provider.py +++ b/tests/test_provider.py @@ -1,5 +1,5 @@ def test_basic(account, second_account, networks, eth_tester_provider): - receipt = account.transfer(account, 100) + receipt = account.transfer(second_account, 100) assert not receipt.failed assert receipt.value == 100