From 4dd498217cb5f9a0aa22005bf90ec1656cce4975 Mon Sep 17 00:00:00 2001 From: LucasCambon Date: Wed, 21 May 2025 18:46:10 -0300 Subject: [PATCH 1/3] Update: update etherscan url to v2 from v1 and tests --- src/ethproto/wrappers.py | 5 ++-- tests/test_w3.py | 49 ++++++++++++++++++++++++++++++++++++++++ tox.ini | 1 + 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/ethproto/wrappers.py b/src/ethproto/wrappers.py index 4316012..45512fa 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}&") AMOUNT_DECIMALS = env.int("AMOUNT_DECIMALS", 18) AMOUNT_CLASSNAME = env.str("AMOUNT_CLASSNAME", None) @@ -273,9 +273,10 @@ def get_first_block(self, eth_wrapper): if not etherscan_url: return 0 address = self.get_contract_address(eth_wrapper) + chain_id = self.w3.eth.chain_id url = ( etherscan_url - + f"&module=account&action=txlist&address={address}&startblock=0&" + + f"chainid={chain_id}&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..cb21b0a 100644 --- a/tests/test_w3.py +++ b/tests/test_w3.py @@ -1,4 +1,6 @@ +import importlib import os +import sys import pytest from web3 import Web3 @@ -11,6 +13,32 @@ ] +@pytest.fixture +def provider_with_etherscan_env(mocker): + mocker.patch.dict( + os.environ, + { + "ETHERSCAN_URL": "https://{domain}/v2/api?apikey={token}&", + "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 +210,24 @@ 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 + assert provider.get_etherscan_url() == "https://api.etherscan.io/v2/api?apikey=abc123&" + + +def test_get_first_block_makes_request(provider_with_etherscan_env, requests_mock): + provider = provider_with_etherscan_env + address = "0x8e3aab1fc53e8b0f5d987c20b1899a2db3b2f95c" # random generated address + chain_id = provider.w3.eth.chain_id + + requests_mock.get( + f"https://api.etherscan.io/v2/api?apikey=abc123&" + f"chainid={chain_id}&module=account&action=txlist&address={address}&startblock=0&" + "endblock=99999999&page=1&offset=10&sort=asc", + json={"status": "1", "message": "OK", "result": [{"blockNumber": "1"}]}, + ) + + block = provider.get_first_block(DummyWrapper()) + assert block == 1 diff --git a/tox.ini b/tox.ini index 7a88287..ab02cd0 100644 --- a/tox.ini +++ b/tox.ini @@ -26,6 +26,7 @@ extras = testing deps = warrant @ git+https://github.com/gnarvaja/warrant.git#egg=warrant + requests-mock commands = pytest --block-network {posargs} From 6522fa007b6e513218900ccd1904a4912d45cb40 Mon Sep 17 00:00:00 2001 From: LucasCambon Date: Wed, 21 May 2025 21:21:56 -0300 Subject: [PATCH 2/3] Using responses in test added to setup. Refactor to etherscan_url & get url to use chainid --- setup.cfg | 1 + src/ethproto/wrappers.py | 8 ++++---- tests/test_w3.py | 25 +++++++++++++------------ tox.ini | 1 - 4 files changed, 18 insertions(+), 17 deletions(-) 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 45512fa..0ff6d4d 100644 --- a/src/ethproto/wrappers.py +++ b/src/ethproto/wrappers.py @@ -17,7 +17,8 @@ ETHERSCAN_TOKEN = env.str("ETHERSCAN_TOKEN", None) ETHERSCAN_DOMAIN = env.str("ETHERSCAN_DOMAIN", "api.etherscan.io") -ETHERSCAN_URL = env.str("ETHERSCAN_URL", "https://{domain}/v2/api?apikey={token}&") +ETHERSCAN_CHAIN = env.str("ETHERSCAN_CHAIN", 137) +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,17 +267,16 @@ 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=ETHERSCAN_CHAIN) def get_first_block(self, eth_wrapper): etherscan_url = self.get_etherscan_url() if not etherscan_url: return 0 address = self.get_contract_address(eth_wrapper) - chain_id = self.w3.eth.chain_id url = ( etherscan_url - + f"chainid={chain_id}&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 cb21b0a..df39d58 100644 --- a/tests/test_w3.py +++ b/tests/test_w3.py @@ -3,6 +3,7 @@ import sys import pytest +import responses from web3 import Web3 from ethproto import w3wrappers, wrappers @@ -17,11 +18,7 @@ def provider_with_etherscan_env(mocker): mocker.patch.dict( os.environ, - { - "ETHERSCAN_URL": "https://{domain}/v2/api?apikey={token}&", - "ETHERSCAN_TOKEN": "abc123", - "ETHERSCAN_DOMAIN": "api.etherscan.io", - }, + {"ETHERSCAN_TOKEN": "abc123", "ETHERSCAN_DOMAIN": "api.etherscan.io", "ETHERSCAN_CHAIN": "137"}, ) sys.modules.pop("ethproto.wrappers", None) sys.modules.pop("ethproto.w3wrappers", None) @@ -214,20 +211,24 @@ def test_sign_and_send_interact_with_existing_contract(sign_and_send): def test_get_etherscan_url_v2_format(provider_with_etherscan_env): provider = provider_with_etherscan_env - assert provider.get_etherscan_url() == "https://api.etherscan.io/v2/api?apikey=abc123&" + assert provider.get_etherscan_url() == "https://api.etherscan.io/v2/api?apikey=abc123&chainid=137&" -def test_get_first_block_makes_request(provider_with_etherscan_env, requests_mock): +@responses.activate +def test_get_first_block_makes_request(provider_with_etherscan_env): provider = provider_with_etherscan_env - address = "0x8e3aab1fc53e8b0f5d987c20b1899a2db3b2f95c" # random generated address - chain_id = provider.w3.eth.chain_id + address = "0x8e3aab1fc53e8b0f5d987c20b1899a2db3b2f95c" - requests_mock.get( - f"https://api.etherscan.io/v2/api?apikey=abc123&" - f"chainid={chain_id}&module=account&action=txlist&address={address}&startblock=0&" + responses.get( + f"https://api.etherscan.io/v2/api?apikey=abc123&chainid=137&" + 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") diff --git a/tox.ini b/tox.ini index ab02cd0..7a88287 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,6 @@ extras = testing deps = warrant @ git+https://github.com/gnarvaja/warrant.git#egg=warrant - requests-mock commands = pytest --block-network {posargs} From dc57e8e526fcf5dd4f6e75150503af30e964180b Mon Sep 17 00:00:00 2001 From: LucasCambon Date: Thu, 22 May 2025 13:06:12 -0300 Subject: [PATCH 3/3] Fix: using w3 chain_id instead of env variable --- src/ethproto/wrappers.py | 5 +++-- tests/test_w3.py | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ethproto/wrappers.py b/src/ethproto/wrappers.py index 0ff6d4d..89b9417 100644 --- a/src/ethproto/wrappers.py +++ b/src/ethproto/wrappers.py @@ -17,7 +17,6 @@ ETHERSCAN_TOKEN = env.str("ETHERSCAN_TOKEN", None) ETHERSCAN_DOMAIN = env.str("ETHERSCAN_DOMAIN", "api.etherscan.io") -ETHERSCAN_CHAIN = env.str("ETHERSCAN_CHAIN", 137) 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) @@ -267,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, chainid=ETHERSCAN_CHAIN) + 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() diff --git a/tests/test_w3.py b/tests/test_w3.py index df39d58..dffe357 100644 --- a/tests/test_w3.py +++ b/tests/test_w3.py @@ -18,7 +18,7 @@ def provider_with_etherscan_env(mocker): mocker.patch.dict( os.environ, - {"ETHERSCAN_TOKEN": "abc123", "ETHERSCAN_DOMAIN": "api.etherscan.io", "ETHERSCAN_CHAIN": "137"}, + {"ETHERSCAN_TOKEN": "abc123", "ETHERSCAN_DOMAIN": "api.etherscan.io"}, ) sys.modules.pop("ethproto.wrappers", None) sys.modules.pop("ethproto.w3wrappers", None) @@ -211,16 +211,17 @@ def test_sign_and_send_interact_with_existing_contract(sign_and_send): def test_get_etherscan_url_v2_format(provider_with_etherscan_env): provider = provider_with_etherscan_env - assert provider.get_etherscan_url() == "https://api.etherscan.io/v2/api?apikey=abc123&chainid=137&" + 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=137&" + 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"}]},