Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
5 changes: 3 additions & 2 deletions docs/abi_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ Ethereum Addresses

All addresses must be supplied in one of three ways:

* While connected to mainnet, an Ethereum Name Service name (often in the form ``myname.eth``)
* A 20-byte hexadecimal that is checksummed using the `EIP-55
<https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md>`_ spec.
* A 20-byte binary address.
* A 20-byte binary address (python bytes type).
* While connected to an Ethereum Name Service (ENS) supported chain, an ENS name
(often in the form ``myname.eth``).

Disabling Strict Bytes Type Checking
------------------------------------
Expand Down
8 changes: 5 additions & 3 deletions docs/middleware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Sync middlewares include:
Async middlewares include:

* ``gas_price_strategy``
* ``name_to_address``
* ``attrdict``
* ``validation``
* ``gas_estimate``
Expand All @@ -66,15 +67,16 @@ AttributeDict
~~~~~~~~~~~~~~~~~~~~~

.. py:method:: web3.middleware.name_to_address_middleware
web3.middleware.async_name_to_address_middleware

This middleware converts Ethereum Name Service (ENS) names into the
address that the name points to. For example :meth:`w3.eth.send_transaction <web3.eth.Eth.send_transaction>` will
accept .eth names in the 'from' and 'to' fields.

.. note::
This middleware only converts ENS names if invoked with the mainnet
(where the ENS contract is deployed), for all other cases will result in an
``InvalidAddress`` error
This middleware only converts ENS names on chains where the proper ENS
contracts are deployed to support this functionality. All other cases will
result in a ``NameNotFound`` error.

Gas Price Strategy
~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
1 change: 1 addition & 0 deletions newsfragments/3012.docs.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update documentation relating to ENS only being available on mainnet. ENS is available on all networks where the ENS contracts are deployed.
1 change: 1 addition & 0 deletions newsfragments/3012.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add async support for ENS name-to-address resolution via ``async_name_to_address_middleware``.
6 changes: 4 additions & 2 deletions tests/core/manager/test_default_middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
async_attrdict_middleware,
async_buffered_gas_estimate_middleware,
async_gas_price_strategy_middleware,
async_name_to_address_middleware,
async_validation_middleware,
attrdict_middleware,
buffered_gas_estimate_middleware,
Expand All @@ -15,7 +16,7 @@
)


def test_default_sync_middlwares(w3):
def test_default_sync_middlewares(w3):
expected_middlewares = [
(gas_price_strategy_middleware, "gas_price_strategy"),
(name_to_address_middleware(w3), "name_to_address"),
Expand All @@ -32,9 +33,10 @@ def test_default_sync_middlwares(w3):
assert default_middlewares[x][1] == expected_middlewares[x][1]


def test_default_async_middlwares():
def test_default_async_middlewares():
expected_middlewares = [
(async_gas_price_strategy_middleware, "gas_price_strategy"),
(async_name_to_address_middleware, "name_to_address"),
(async_attrdict_middleware, "attrdict"),
(async_validation_middleware, "validation"),
(async_buffered_gas_estimate_middleware, "gas_estimate"),
Expand Down
182 changes: 152 additions & 30 deletions tests/core/middleware/test_name_to_address_middleware.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import pytest

import pytest_asyncio

from web3 import (
AsyncWeb3,
Web3,
constants,
)
from web3.exceptions import (
InvalidAddress,
NameNotFound,
)
from web3.middleware import ( # noqa: F401
construct_fixture_middleware,
from web3.middleware import (
name_to_address_middleware,
)
from web3.providers.base import (
BaseProvider,
from web3.middleware.names import (
async_name_to_address_middleware,
)
from web3.providers.eth_tester import (
AsyncEthereumTesterProvider,
EthereumTesterProvider,
)

NAME = "dump.eth"
ADDRESS = constants.ADDRESS_ZERO
BALANCE = 0
NAME = "tester.eth"


class TempENS:
Expand All @@ -29,31 +32,150 @@ def address(self, name):


@pytest.fixture
def w3():
w3 = Web3(provider=BaseProvider(), middlewares=[])
w3.ens = TempENS({NAME: ADDRESS})
w3.middleware_onion.add(name_to_address_middleware(w3))
return w3
def _w3_setup():
return Web3(provider=EthereumTesterProvider(), middlewares=[])


@pytest.fixture
def ens_mapped_address(_w3_setup):
return _w3_setup.eth.accounts[0]


@pytest.fixture
def ens_addr_account_balance(ens_mapped_address, _w3_setup):
return _w3_setup.eth.get_balance(ens_mapped_address)


@pytest.fixture
def w3(_w3_setup, ens_mapped_address):
_w3_setup.ens = TempENS({NAME: ens_mapped_address})
_w3_setup.middleware_onion.add(name_to_address_middleware(_w3_setup))
return _w3_setup


@pytest.mark.parametrize(
"params",
(
[NAME, "latest"],
[NAME, 0],
[NAME],
),
)
def test_pass_name_resolver_get_balance_list_args(
w3,
ens_addr_account_balance,
params,
):
assert w3.eth.get_balance(*params) == ens_addr_account_balance

def test_pass_name_resolver(w3):
return_chain_on_mainnet = construct_fixture_middleware(

@pytest.mark.parametrize(
"params",
(
{"value": 1, "from": NAME, "to": NAME, "gas": 21000},
{
"net_version": "1",
}
)
return_balance = construct_fixture_middleware({"eth_getBalance": BALANCE})
w3.middleware_onion.inject(return_chain_on_mainnet, layer=0)
w3.middleware_onion.inject(return_balance, layer=0)
assert w3.eth.get_balance(NAME) == BALANCE
"value": 1,
"maxPriorityFeePerGas": 10**9,
"from": NAME,
"to": NAME,
"gas": 21000,
},
{"value": 1, "to": NAME, "gas": 21000, "from": NAME},
),
)
def test_pass_name_resolver_send_transaction_dict_args(
w3,
params,
ens_mapped_address,
):
tx_hash = w3.eth.send_transaction(params)

tx = w3.eth.get_transaction(tx_hash)
assert tx["from"] == ens_mapped_address
assert tx["to"] == ens_mapped_address


def test_fail_name_resolver(w3):
return_chain_on_mainnet = construct_fixture_middleware(
{
"net_version": "2",
}
)
w3.middleware_onion.inject(return_chain_on_mainnet, layer=0)
with pytest.raises(InvalidAddress, match=r".*ethereum\.eth.*"):
with pytest.raises(NameNotFound, match=r".*ethereum\.eth.*"):
w3.eth.get_balance("ethereum.eth")


# --- async --- #


class AsyncTempENS(TempENS):
async def address(self, name):
return self.registry.get(name, None)


@pytest_asyncio.fixture
async def _async_w3_setup():
return AsyncWeb3(provider=AsyncEthereumTesterProvider(), middlewares=[])


@pytest_asyncio.fixture
async def async_ens_mapped_address(_async_w3_setup):
accts = await _async_w3_setup.eth.accounts
return accts[0]


@pytest_asyncio.fixture
async def async_ens_addr_account_balance(async_ens_mapped_address, _async_w3_setup):
return await _async_w3_setup.eth.get_balance(async_ens_mapped_address)


@pytest_asyncio.fixture
async def async_w3(_async_w3_setup, async_ens_mapped_address):
_async_w3_setup.ens = AsyncTempENS({NAME: async_ens_mapped_address})
_async_w3_setup.middleware_onion.add(async_name_to_address_middleware)
return _async_w3_setup


@pytest.mark.asyncio
@pytest.mark.parametrize(
"params",
(
[NAME, "latest"],
[NAME, 0],
[NAME],
),
)
async def test_async_pass_name_resolver_get_balance_list_args(
async_w3,
async_ens_addr_account_balance,
params,
):
assert await async_w3.eth.get_balance(*params) == async_ens_addr_account_balance


@pytest.mark.asyncio
@pytest.mark.parametrize(
"params",
(
{"value": 1, "from": NAME, "to": NAME, "gas": 21000},
{
"value": 1,
"maxPriorityFeePerGas": 10**9,
"from": NAME,
"to": NAME,
"gas": 21000,
},
{"value": 1, "to": NAME, "gas": 21000, "from": NAME},
),
)
async def test_async_pass_name_resolver_send_transaction_dict_args(
async_w3,
params,
async_ens_mapped_address,
):
tx_hash = await async_w3.eth.send_transaction(params)

tx = await async_w3.eth.get_transaction(tx_hash)
assert tx["from"] == async_ens_mapped_address
assert tx["to"] == async_ens_mapped_address


@pytest.mark.asyncio
async def test_async_fail_name_resolver(async_w3):
with pytest.raises(NameNotFound, match=r".*ethereum\.eth.*"):
await async_w3.eth.get_balance("ethereum.eth")
7 changes: 6 additions & 1 deletion tests/core/providers/test_async_http_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
async_attrdict_middleware,
async_buffered_gas_estimate_middleware,
async_gas_price_strategy_middleware,
async_name_to_address_middleware,
async_validation_middleware,
)
from web3.net import (
Expand Down Expand Up @@ -81,12 +82,16 @@ def test_web3_with_async_http_provider_has_default_middlewares_and_modules() ->

# the following length check should fail and will need to be added to once more
# async middlewares are added to the defaults
assert len(async_w3.middleware_onion.middlewares) == 4
assert len(async_w3.middleware_onion.middlewares) == 5

assert (
async_w3.middleware_onion.get("gas_price_strategy")
== async_gas_price_strategy_middleware
)
assert (
async_w3.middleware_onion.get("name_to_address")
== async_name_to_address_middleware
)
assert async_w3.middleware_onion.get("attrdict") == async_attrdict_middleware
assert async_w3.middleware_onion.get("validation") == async_validation_middleware
assert (
Expand Down
Loading