Repository: ethereum/web3.py

Issue:
Add 'account' to AsyncEth?
Hey 👋 Is there a reason `account` is not available in `AsyncEth`?

So far, I had to create a non-async w3 object to sign transactions. However, I just found out that when I subclass AsyncEth like this
```python
class CustomAsyncEth(AsyncEth):
    account = Account()
```
signing transactions works just fine.

Discussion:
dbfreem: So, I did some thinking about the test here. Two things I thought of.

1.  Most of these test are testing the functionality of `eth_account.Account`. It could be argued that these test don't really belong in web3.py but actually in eth_account. They are actually probably already covered there.
2. If we do need test for this, shouldn't the test be only on BaseEth instead of duplicating them between AsyncEth and Eth? I could change the above referenced test to be only one set of test against `BaseEth.account`.

Just my thoughts so feel free to say "yes, we want both the AsynEth and Eth test in web3.py for account". :) haha.
kclowes: Thanks for the comments!

> 1. Most of these test are testing the functionality of eth_account.Account. It could be argued that these test don't really belong in web3.py but actually in eth_account. They are actually probably already covered there.

They are covered over there as well, but I think it's good to make sure we can access the most important methods through `w3.eth.account`, rather than just on the `Account` class. For example, when the HDWallet feature was implemented, it was working great in `eth-account`, but we had to do some tweaking to get it to work in web3. 

> 2. If we do need test for this, shouldn't the test be only on BaseEth instead of duplicating them between AsyncEth and Eth? I could change the above referenced test to be only one set of test against BaseEth.account.

That's a good idea. I think it would be good to have at least one "happy path" test for each `Eth` and `AsyncEth` to make sure we can access `account` through each of those classes to prevent any regressions though.
dbfreem: @kclowes  take a look at this and let me know what you think
dbfreem: @fselmo I made the suggested changes. Copied your test into test_account.py, and made the doc changes. 
fselmo: > @fselmo I made the suggested changes. Copied your test into test_account.py, and made the doc changes.

lgtm! I just organized async at the bottom so it's a bit easier to read. Ty 👍🏼... I'll merge as soon as tests pass

Patch:
diff --git a/docs/providers.rst b/docs/providers.rst
index 2b0b7a20..293b9097 100644
--- a/docs/providers.rst
+++ b/docs/providers.rst
@@ -411,6 +411,7 @@ Supported Methods
 
 Eth
 ***
+- :class:`web3.eth.account <eth_account.account.Account>`
 - :meth:`web3.eth.accounts <web3.eth.Eth.accounts>`
 - :meth:`web3.eth.block_number <web3.eth.Eth.block_number>`
 - :meth:`web3.eth.chain_id <web3.eth.Eth.chain_id>`
diff --git a/newsfragments/2580.feature.rst b/newsfragments/2580.feature.rst
new file mode 100644
index 00000000..26b12fbf
--- /dev/null
+++ b/newsfragments/2580.feature.rst
@@ -0,0 +1,1 @@
+Moved `Eth.account` to `BaseEth.account` so that it could be use in `AsyncEth`
diff --git a/web3/eth.py b/web3/eth.py
index 52e3984b..cdb08fd3 100644
--- a/web3/eth.py
+++ b/web3/eth.py
@@ -115,6 +115,7 @@ class BaseEth(Module):
     _default_account: Union[ChecksumAddress, Empty] = empty
     _default_block: BlockIdentifier = "latest"
     gasPriceStrategy = None
+    account = Account()
     defaultContractFactory: Any = None
 
     _gas_price: Method[Callable[[], Wei]] = Method(
@@ -598,7 +599,6 @@ class AsyncEth(BaseEth):
 
 
 class Eth(BaseEth):
-    account = Account()
     defaultContractFactory: Type[Union[Contract, ContractCaller]] = Contract
 
     def namereg(self) -> NoReturn:


Test patch:
diff --git a/tests/core/eth-module/test_accounts.py b/tests/core/eth-module/test_accounts.py
index 3dbf3828..1d3e755d 100644
--- a/tests/core/eth-module/test_accounts.py
+++ b/tests/core/eth-module/test_accounts.py
@@ -1,11 +1,18 @@
 # coding=utf-8
 
 import pytest
+from unittest.mock import (
+    patch,
+)
 
 from eth_account.messages import (
     encode_defunct,
 )
+from eth_account.signers.local import (
+    LocalAccount,
+)
 from eth_utils import (
+    is_bytes,
     is_checksum_address,
     to_bytes,
     to_hex,
@@ -21,9 +28,16 @@ from web3 import (
     Account,
     Web3,
 )
+from web3.eth import (
+    AsyncEth,
+    BaseEth,
+)
 from web3.providers.eth_tester import (
     EthereumTesterProvider,
 )
+from web3.providers.eth_tester.main import (
+    AsyncEthereumTesterProvider,
+)
 
 # from https://github.com/ethereum/tests/blob/3930ca3a9a377107d5792b3e7202f79c688f1a67/BasicTests/txtest.json # noqa: 501
 ETH_TEST_TRANSACTIONS = [
@@ -77,7 +91,7 @@ def web3js_password():
 @pytest.fixture(params=["instance", "class"])
 def acct(request, w3):
     if request.param == "instance":
-        return w3.eth.account
+        return BaseEth(w3).account
     elif request.param == "class":
         return Account
     raise Exception("Unreachable!")
@@ -536,3 +550,26 @@ def test_eth_account_sign_and_send_EIP155_transaction_to_eth_tester(
     assert actual_txn.r == r
     assert actual_txn.s == s
     assert actual_txn.v == v
+
+
+# -- async -- #
+
+
+@pytest.fixture()
+def async_w3():
+    return Web3(AsyncEthereumTesterProvider(), modules={"eth": [AsyncEth]})
+
+
+@patch("web3.eth.BaseEth.account", "wired via BaseEth")
+def test_account_is_wired_via_base_eth_for_sync_and_async(w3, async_w3):
+    # this gives us some comfort that all the `w3` tests would apply for `async_w3` as
+    # well, since `Account` is static and not actually awaited
+    assert w3.eth.account == "wired via BaseEth"
+    assert async_w3.eth.account == "wired via BaseEth"
+
+
+def test_async_eth_account_creates_account(async_w3):
+    account = async_w3.eth.account.create()
+    assert isinstance(account, LocalAccount)
+    assert is_checksum_address(account.address)
+    assert is_bytes(account.privateKey)