mm-eth 0.5.10__py3-none-any.whl → 0.5.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mm_eth/async_rpc.py CHANGED
@@ -1,9 +1,10 @@
1
1
  import json
2
+ from collections.abc import Sequence
2
3
  from typing import Any
3
4
 
4
5
  import websockets
5
6
  from mm_crypto_utils import Nodes, Proxies, random_node, random_proxy
6
- from mm_std import Err, Ok, Result, ahr
7
+ from mm_std import Err, Ok, Result, hra
7
8
 
8
9
  from mm_eth.utils import hex_str_to_int
9
10
 
@@ -12,9 +13,9 @@ async def rpc_call(
12
13
  *,
13
14
  nodes: Nodes,
14
15
  method: str,
15
- params: list[object],
16
+ params: Sequence[object],
16
17
  id_: int = 1,
17
- timeout: int = 10,
18
+ timeout: float = 10,
18
19
  proxies: Proxies = None,
19
20
  attempts: int = 1,
20
21
  ) -> Result[Any]:
@@ -32,8 +33,8 @@ async def rpc_call(
32
33
  return res
33
34
 
34
35
 
35
- async def _http_call(node: str, data: dict[str, object], timeout: int, proxy: str | None) -> Result[Any]:
36
- res = await ahr(node, method="POST", proxy=proxy, timeout=timeout, params=data, json_params=True)
36
+ async def _http_call(node: str, data: dict[str, object], timeout: float, proxy: str | None) -> Result[Any]:
37
+ res = await hra(node, method="POST", proxy=proxy, timeout=timeout, params=data, json_params=True)
37
38
  if res.is_error():
38
39
  return res.to_err_result()
39
40
  try:
@@ -47,7 +48,7 @@ async def _http_call(node: str, data: dict[str, object], timeout: int, proxy: st
47
48
  return res.to_err_result(f"exception: {err}")
48
49
 
49
50
 
50
- async def _ws_call(node: str, data: dict[str, object], timeout: int) -> Result[Any]:
51
+ async def _ws_call(node: str, data: dict[str, object], timeout: float) -> Result[Any]:
51
52
  try:
52
53
  async with websockets.connect(node, timeout=timeout) as ws:
53
54
  await ws.send(json.dumps(data))
mm_eth/ens.py CHANGED
@@ -1,7 +1,14 @@
1
+ from ens.utils import normal_name_to_hash
1
2
  from mm_crypto_utils import Nodes, Proxies, random_node, random_proxy
2
3
  from mm_std import Err, Ok, Result
4
+ from web3 import Web3
3
5
 
4
- from mm_eth.utils import get_async_w3, get_w3
6
+ from mm_eth.async_rpc import rpc_call
7
+ from mm_eth.utils import get_w3
8
+
9
+ ENS_REGISTRY_ADDRESS: str = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
10
+ FUNC_SELECTOR_RESOLVER: str = "0x0178b8bf" # resolver(bytes32)
11
+ FUNC_SELECTOR_NAME: str = "0x691f3431" # name(bytes32)
5
12
 
6
13
 
7
14
  def get_name_with_retries(
@@ -25,27 +32,75 @@ def get_name(rpc_url: str, address: str, timeout: float = 5, proxy: str | None =
25
32
  error = e.__class__.__qualname__
26
33
  return Err("exception: " + error)
27
34
 
35
+ # async def async_get_name(rpc_url: str, address: str, timeout: float = 5, proxy: str | None = None) -> Result[str | None]:
36
+ # w3 = await get_async_w3(rpc_url, timeout=timeout, proxy=proxy)
37
+ # try:
38
+ # res = await w3.ens.name(w3.to_checksum_address(address)) # type: ignore[union-attr]
39
+ # return Ok(res)
40
+ # except Exception as e:
41
+ # error = str(e)
42
+ # if not error:
43
+ # error = e.__class__.__qualname__
44
+ # return Err("exception: " + error)
45
+ # finally:
46
+ # await w3.provider.disconnect()
47
+
48
+
49
+ async def get_name_async(rpc_url: str, address: str, timeout: float = 5, proxy: str | None = None) -> Result[str | None]:
50
+ checksum_addr: str = Web3.to_checksum_address(address)
51
+ reverse_name: str = checksum_addr.lower()[2:] + ".addr.reverse"
52
+ name_hash_hex: str = normal_name_to_hash(reverse_name).hex()
53
+
54
+ resolver_data: str = FUNC_SELECTOR_RESOLVER + name_hash_hex
55
+
56
+ resolver_params = [{"to": ENS_REGISTRY_ADDRESS, "data": resolver_data}, "latest"]
57
+
58
+ resolver_res: Result[str] = await rpc_call(
59
+ nodes=rpc_url,
60
+ method="eth_call",
61
+ params=resolver_params,
62
+ timeout=timeout,
63
+ proxies=proxy,
64
+ attempts=1,
65
+ )
66
+ if not isinstance(resolver_res, Ok) or len(resolver_res.ok) != 66:
67
+ return Ok(None)
68
+
69
+ resolver_address: str = Web3.to_checksum_address("0x" + resolver_res.ok[-40:])
70
+
71
+ name_data: str = FUNC_SELECTOR_NAME + name_hash_hex
72
+ name_params = [{"to": resolver_address, "data": name_data}, "latest"]
73
+
74
+ name_res: Result[str] = await rpc_call(
75
+ nodes=rpc_url,
76
+ method="eth_call",
77
+ params=name_params,
78
+ timeout=timeout,
79
+ proxies=proxy,
80
+ attempts=1,
81
+ )
82
+
83
+ if isinstance(name_res, Err):
84
+ return name_res
85
+ if name_res.ok == "0x":
86
+ return Ok(None)
28
87
 
29
- async def async_get_name(rpc_url: str, address: str, timeout: float = 5, proxy: str | None = None) -> Result[str | None]:
30
- w3 = await get_async_w3(rpc_url, timeout=timeout, proxy=proxy)
31
88
  try:
32
- res = await w3.ens.name(w3.to_checksum_address(address)) # type: ignore[union-attr]
33
- return Ok(res)
89
+ hex_data: str = name_res.ok
90
+ length_hex: str = hex_data[66:130]
91
+ str_len: int = int(length_hex, 16) * 2
92
+ name_hex: str = hex_data[130 : 130 + str_len]
93
+ return Ok(bytes.fromhex(name_hex).decode("utf-8"))
34
94
  except Exception as e:
35
- error = str(e)
36
- if not error:
37
- error = e.__class__.__qualname__
38
- return Err("exception: " + error)
39
- finally:
40
- await w3.provider.disconnect()
95
+ return Err(e)
41
96
 
42
97
 
43
- async def async_get_name_with_retries(
98
+ async def get_name_with_retries_async(
44
99
  rpc_urls: Nodes, address: str, retries: int, timeout: float = 5, proxies: Proxies = None
45
100
  ) -> Result[str | None]:
46
101
  res: Result[str | None] = Err("not started yet")
47
102
  for _ in range(retries):
48
- res = await async_get_name(random_node(rpc_urls), address, timeout=timeout, proxy=random_proxy(proxies))
103
+ res = await get_name_async(random_node(rpc_urls), address, timeout=timeout, proxy=random_proxy(proxies))
49
104
  if res.is_ok():
50
105
  return res
51
106
  return res
mm_eth/utils.py CHANGED
@@ -196,6 +196,8 @@ def get_w3(rpc_url: str, timeout: float | None = None, proxy: str | None = None)
196
196
 
197
197
 
198
198
  async def get_async_w3(rpc_url: str, timeout: float | None = None, proxy: str | None = None) -> AsyncWeb3:
199
+ # TODO: Don't use async w3. AsyncHTTPProvider uses threads
200
+ # check its constructor: self._request_session_manager = HTTPSessionManager()
199
201
  request_kwargs: dict[str, object] = {"timeout": timeout}
200
202
  if proxy and proxy.startswith("http"):
201
203
  request_kwargs["proxy"] = proxy
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-eth
3
- Version: 0.5.10
3
+ Version: 0.5.12
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: aiohttp-socks~=0.10.1
6
- Requires-Dist: mm-crypto-utils>=0.2.9
6
+ Requires-Dist: mm-crypto-utils>=0.2.10
7
+ Requires-Dist: mm-std~=0.3.22
7
8
  Requires-Dist: typer>=0.15.2
8
- Requires-Dist: web3~=7.9.0
9
+ Requires-Dist: web3~=7.10.0
9
10
  Requires-Dist: websocket-client~=1.8.0
@@ -2,10 +2,10 @@ mm_eth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  mm_eth/abi.py,sha256=Qf-QOsR9QexyQM9XWKNeTMkRarIL3XQJbaDbJ8ifMrw,4856
3
3
  mm_eth/account.py,sha256=k0MNMatBe0zo1iKZiB_Tq6zyEIo22IncD6ewNUJp3dY,2075
4
4
  mm_eth/anvil.py,sha256=98RCfI7dEpxFBTV6UErYvubWVP3n0ctUFn1--4kZ84U,1603
5
- mm_eth/async_rpc.py,sha256=8rMtg3Hr6Pn7NaFROxxWsXQSM8wJ92EUYlOOoc6_TOk,2934
5
+ mm_eth/async_rpc.py,sha256=zjPcOoC-NTjMxbWu6cRQn-knHEQ75ZO5L-KZoaiwUJ0,2981
6
6
  mm_eth/constants.py,sha256=Cy_G-IleBH4gAZ4ok8AGHHlqmdW0ZM7ZldyVpzAfWLs,54
7
7
  mm_eth/deploy.py,sha256=SB3ruY808_5UnG8kHR34uVP66P3zOWZu0ImKD7UUv2s,691
8
- mm_eth/ens.py,sha256=x36ttvVtpwbi6iZ2AuPiOSRxz2WVoVVGLbMun_AmZgg,1918
8
+ mm_eth/ens.py,sha256=lH3TZABYFBiEEtWlyxCqrcYC-nZQsI_1wSCMzBzHPrM,3860
9
9
  mm_eth/erc20.py,sha256=LZmTkjmXpN7sUhOtSLiTqb8Ubet9C9q32EQwTS78OqE,7378
10
10
  mm_eth/ethernodes.py,sha256=V4VVbC6Nr9jhwT7blxtLugXC5KfXqE8n-kP0VvGHbqo,3070
11
11
  mm_eth/json_encoder.py,sha256=S4oD-qfTVztMb4sRpY1puhBQwOBofTyQXWszmdXk4og,433
@@ -13,7 +13,7 @@ mm_eth/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  mm_eth/rpc.py,sha256=k0eHxo_Dp6G0fHQ_rD-QbwOJz5ngC6kxBjl5NEHnyw8,13832
14
14
  mm_eth/solc.py,sha256=dYRvT8PjZlLDZhNsc_-0790Eug_ZwU2G-iBfIdGj6wQ,1071
15
15
  mm_eth/tx.py,sha256=efSoMCoWkenbGdHo1_LX66_Edz1HvED5-J_i3wrHwMw,4051
16
- mm_eth/utils.py,sha256=bkh4EBaxTYEnrR1s7zQ2hzZCwXw1r-2HmfN-dpTXwRc,8069
16
+ mm_eth/utils.py,sha256=FytG3U6h80mnUaKP8W2mPZ77EuOp4U7pVbPuoKI3wW4,8215
17
17
  mm_eth/vault.py,sha256=h8NyiOQh5YFskh1lZA3KyvnJUnxl9769ME2ChplG0CM,1477
18
18
  mm_eth/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  mm_eth/cli/calcs.py,sha256=cLFTYNAN-I53tUiSg-zFfVr2afjIZPftDDjHj16FBz0,1068
@@ -42,7 +42,7 @@ mm_eth/cli/cmd/wallet/private_key_cmd.py,sha256=Fv_2OLog1h32pIP7PJITwl_pHdy3BXva
42
42
  mm_eth/cli/examples/balances.toml,sha256=i_ALpiEcf8-0TFiUg1cgJhxxfHYeBl9x0b3tnUWjswU,421
43
43
  mm_eth/cli/examples/call_contract.toml,sha256=ZQWK-409V_vLIZ2bsRD5RCWPPzShPz2KJTTRQY4YaGw,248
44
44
  mm_eth/cli/examples/transfer.toml,sha256=8mWuphDquoSDJw-hb9VJqtonjmv3kJ5Ip8jJ4t5YnfM,1810
45
- mm_eth-0.5.10.dist-info/METADATA,sha256=nEXmDDRgaktmWuPWKrDuxSaVv0ppfYB6-wyxqApmy6c,245
46
- mm_eth-0.5.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
- mm_eth-0.5.10.dist-info/entry_points.txt,sha256=aGhpsozl8NIrkuUcX5fSgURCcDhr3ShUdeTSIrJq4oc,46
48
- mm_eth-0.5.10.dist-info/RECORD,,
45
+ mm_eth-0.5.12.dist-info/METADATA,sha256=Hj0xMr3BCxx3MxKT-e5C6cQMO9tHQ0XJhjFbA4teqDA,277
46
+ mm_eth-0.5.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
+ mm_eth-0.5.12.dist-info/entry_points.txt,sha256=aGhpsozl8NIrkuUcX5fSgURCcDhr3ShUdeTSIrJq4oc,46
48
+ mm_eth-0.5.12.dist-info/RECORD,,