diff --git a/setup.cfg b/setup.cfg index 70d445a..6ad26d4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -80,6 +80,7 @@ testing = pytest-cov pytest-mock pytest-recording + responses setuptools web3[tester]==7.* diff --git a/src/ethproto/wrappers.py b/src/ethproto/wrappers.py index 4316012..89b9417 100644 --- a/src/ethproto/wrappers.py +++ b/src/ethproto/wrappers.py @@ -17,7 +17,7 @@ ETHERSCAN_TOKEN = env.str("ETHERSCAN_TOKEN", None) ETHERSCAN_DOMAIN = env.str("ETHERSCAN_DOMAIN", "api.etherscan.io") -ETHERSCAN_URL = env.str("ETHERSCAN_URL", "https://{domain}/api?apikey={token}&") +ETHERSCAN_URL = env.str("ETHERSCAN_URL", "https://{domain}/v2/api?apikey={token}&chainid={chainid}&") AMOUNT_DECIMALS = env.int("AMOUNT_DECIMALS", 18) AMOUNT_CLASSNAME = env.str("AMOUNT_CLASSNAME", None) @@ -266,7 +266,9 @@ def get_events(self, eth_wrapper, event_name, filter_kwargs={}): def get_etherscan_url(self): if ETHERSCAN_TOKEN is None: return None - return ETHERSCAN_URL.format(token=ETHERSCAN_TOKEN, domain=ETHERSCAN_DOMAIN) + return ETHERSCAN_URL.format( + token=ETHERSCAN_TOKEN, domain=ETHERSCAN_DOMAIN, chainid=self.w3.eth.chain_id + ) def get_first_block(self, eth_wrapper): etherscan_url = self.get_etherscan_url() @@ -275,7 +277,7 @@ def get_first_block(self, eth_wrapper): address = self.get_contract_address(eth_wrapper) url = ( etherscan_url - + f"&module=account&action=txlist&address={address}&startblock=0&" + + f"module=account&action=txlist&address={address}&startblock=0&" + "endblock=99999999&page=1&offset=10&sort=asc" ) resp = requests.get(url) diff --git a/tests/test_w3.py b/tests/test_w3.py index 0dee479..dffe357 100644 --- a/tests/test_w3.py +++ b/tests/test_w3.py @@ -1,6 +1,9 @@ +import importlib import os +import sys import pytest +import responses from web3 import Web3 from ethproto import w3wrappers, wrappers @@ -11,6 +14,28 @@ ] +@pytest.fixture +def provider_with_etherscan_env(mocker): + mocker.patch.dict( + os.environ, + {"ETHERSCAN_TOKEN": "abc123", "ETHERSCAN_DOMAIN": "api.etherscan.io"}, + ) + sys.modules.pop("ethproto.wrappers", None) + sys.modules.pop("ethproto.w3wrappers", None) + wrappers = importlib.import_module("ethproto.wrappers") + w3wrappers = importlib.import_module("ethproto.w3wrappers") + + w3wrappers.register_w3_provider("w3_test", Web3(Web3.EthereumTesterProvider())) + provider = wrappers.get_provider("w3_test") + + return provider + + +class DummyWrapper: + address = "0x8e3aab1fc53e8b0f5d987c20b1899a2db3b2f95c" # random generated address + contract = type("Contract", (), {"address": address})() + + class Counter(wrappers.ETHWrapper): eth_contract = "Counter" # libraries_required = [] @@ -182,3 +207,29 @@ def test_sign_and_send_interact_with_existing_contract(sign_and_send): assert connected.value() == 1 assert counter.value() == 1 # sanity check + + +def test_get_etherscan_url_v2_format(provider_with_etherscan_env): + provider = provider_with_etherscan_env + chainid = provider.w3.eth.chain_id + assert provider.get_etherscan_url() == f"https://api.etherscan.io/v2/api?apikey=abc123&chainid={chainid}&" + + +@responses.activate +def test_get_first_block_makes_request(provider_with_etherscan_env): + provider = provider_with_etherscan_env + address = "0x8e3aab1fc53e8b0f5d987c20b1899a2db3b2f95c" + chainid = provider.w3.eth.chain_id + responses.get( + f"https://api.etherscan.io/v2/api?apikey=abc123&chainid={chainid}&" + f"&module=account&action=txlist&address={address}&startblock=0&" + "endblock=99999999&page=1&offset=10&sort=asc", + json={"status": "1", "message": "OK", "result": [{"blockNumber": "1"}]}, + status=200, + ) + + block = provider.get_first_block(DummyWrapper()) + assert block == 1 + + assert len(responses.calls) == 1 + assert responses.calls[0].request.url.startswith("https://api.etherscan.io")