mm-eth 0.5.17__py3-none-any.whl → 0.6.1__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.
Files changed (45) hide show
  1. mm_eth/abi.py +2 -4
  2. mm_eth/account.py +51 -18
  3. mm_eth/anvil.py +8 -8
  4. mm_eth/cli/calcs.py +1 -16
  5. mm_eth/cli/cli.py +55 -159
  6. mm_eth/cli/cli_utils.py +14 -27
  7. mm_eth/cli/cmd/balance_cmd.py +15 -16
  8. mm_eth/cli/cmd/balances_cmd.py +35 -36
  9. mm_eth/cli/cmd/deploy_cmd.py +9 -11
  10. mm_eth/cli/cmd/node_cmd.py +20 -15
  11. mm_eth/cli/cmd/solc_cmd.py +7 -6
  12. mm_eth/cli/cmd/transfer_cmd.py +210 -128
  13. mm_eth/cli/cmd/wallet/private_key_cmd.py +5 -4
  14. mm_eth/cli/rpc_helpers.py +32 -115
  15. mm_eth/cli/validators.py +13 -16
  16. mm_eth/converters.py +56 -0
  17. mm_eth/erc20.py +6 -224
  18. mm_eth/retry.py +153 -0
  19. mm_eth/rpc.py +230 -428
  20. mm_eth/solc.py +30 -17
  21. mm_eth/tx.py +8 -9
  22. mm_eth/utils.py +0 -224
  23. {mm_eth-0.5.17.dist-info → mm_eth-0.6.1.dist-info}/METADATA +3 -2
  24. mm_eth-0.6.1.dist-info/RECORD +33 -0
  25. mm_eth/async_rpc.py +0 -94
  26. mm_eth/cli/cmd/call_contract_cmd.py +0 -44
  27. mm_eth/cli/cmd/encode_input_data_cmd.py +0 -10
  28. mm_eth/cli/cmd/example_cmd.py +0 -9
  29. mm_eth/cli/cmd/rpc_cmd.py +0 -78
  30. mm_eth/cli/cmd/token_cmd.py +0 -29
  31. mm_eth/cli/cmd/tx_cmd.py +0 -16
  32. mm_eth/cli/cmd/vault_cmd.py +0 -19
  33. mm_eth/cli/examples/balances.toml +0 -18
  34. mm_eth/cli/examples/call_contract.toml +0 -9
  35. mm_eth/cli/examples/transfer.toml +0 -46
  36. mm_eth/cli/print_helpers.py +0 -37
  37. mm_eth/constants.py +0 -1
  38. mm_eth/ens.py +0 -106
  39. mm_eth/ethernodes.py +0 -34
  40. mm_eth/json_encoder.py +0 -15
  41. mm_eth/rpc_async.py +0 -160
  42. mm_eth/vault.py +0 -38
  43. mm_eth-0.5.17.dist-info/RECORD +0 -49
  44. {mm_eth-0.5.17.dist-info → mm_eth-0.6.1.dist-info}/WHEEL +0 -0
  45. {mm_eth-0.5.17.dist-info → mm_eth-0.6.1.dist-info}/entry_points.txt +0 -0
@@ -1,19 +0,0 @@
1
- from pathlib import Path
2
-
3
- import mm_crypto_utils
4
- from mm_std import fatal, print_plain
5
-
6
- from mm_eth import vault
7
- from mm_eth.account import is_private_key
8
-
9
-
10
- def run(keys_url: str, vault_token: str, keys_file: Path) -> None:
11
- private_keys = mm_crypto_utils.read_items_from_file(keys_file, is_private_key)
12
- if not private_keys:
13
- fatal("private keys not found")
14
-
15
- res = vault.set_keys_from_vault(keys_url, vault_token, private_keys)
16
- if res.is_ok() and res.ok is True:
17
- print_plain(f"saved {len(private_keys)} private keys to the vault")
18
- else:
19
- fatal(f"error: {res.err}")
@@ -1,18 +0,0 @@
1
- addresses = """
2
- 0x10fd602Bff689e64D4720D1DCCCD3494f1f16623
3
- 0x58487485c3858109f5A37e42546FE87473f79a4b
4
- 0x97C77B548aE0d4925F5C201220fC6d8996424309
5
- """
6
-
7
- tokens = """
8
- 0x7EdF3b8579c21A8820b4C0B8352541c1CE04045f # USDT
9
- 0x6a55fe4884DE7E1d904BdC47A3BA092240ae9B39 # USDC
10
- """
11
-
12
- nodes = """
13
- https://arb1.arbitrum.io/rpc
14
- https://rpc.arb1.arbitrum.gateway.fm
15
- https://arbitrum-one.publicnode.com
16
- """
17
-
18
- round_ndigits = 3
@@ -1,9 +0,0 @@
1
- contract_address = "0xBa985cad26658EB00eA42aCc7516aed52e7a8AcC"
2
-
3
- function_signature = "balanceOf(address)"
4
-
5
- function_args = "['0x83aC43147BA5dAA5abc4ccEA84F2B8000bA82f26']"
6
-
7
- outputs_types = "uint256" # optional
8
-
9
- node = "https://rpc.eth.gateway.fm"
@@ -1,46 +0,0 @@
1
- # Each line is a transfer instruction, with format: from_address to_address [value]
2
- # Value is optional. If value is not set, default_value will be used
3
- # value is an expression that can contain variable 'balance' and 'random' function
4
- transfers = """
5
- 0x10fd602Bff689e64D4720D1DCCCD3494f1f16623 0x58487485c3858109f5A37e42546FE87473f79a4b 0.1t # comments are allowed here
6
- 0x97C77B548aE0d4925F5C201220fC6d8996424309 0x7EdF3b8579c21A8820b4C0B8352541c1CE04045f 0.2balance-random(0.1t,0.5t)
7
- 0x10ecB8d838746643E613f6B5218C8e342593225c 0xE19242B72a4833eD86F1b2015d4E59052A2b278b
8
- file: /path/to/other_transfers.txt # transfers from this file will be added
9
- """
10
-
11
- private_keys = """
12
- 0x7bb5b9c0ba991275f84b796b4d25fd3a8d7320911f50fade85410e7a2b000632
13
- 0xb7e0b671e176b04ceb0897a698d34771bfe9acf29273dc52a141be6e97145a00
14
- file: /path/to/other_private_keys.txt
15
- """
16
-
17
- token = "0x60631C856303731BE4deb81C0303F80B652aA5b4" # If not specified, it ETH transfers
18
-
19
- max_fee = "1.2base_fee+1gwei+random(1,200)" # 'base_fee' variable is supported
20
-
21
- priority_fee = "1gwei+random(1,12)"
22
-
23
- # Don't transfer if max_fee > max_fee_limit, optional
24
- max_fee_limit = "10.1gwei-random(1,10)"
25
-
26
- gas = "estimate+random(100,200)-19" # 'estimate' variable is supported
27
-
28
- # default_value is used if transfer.value is not set in transfers. It's optional.
29
- default_value = "0.5balance-random(1.5t,3t)+11t" # supported var_name=balance. For ERC20 token use 't' suffix.
30
-
31
- value_min_limit = "0.5t+random(1,2)-7" # don't transfer if transfer.value is less than this
32
-
33
- delay = "random(1.123,10)+1" # secs, optional
34
-
35
- log_debug = "/path/to/file_debug.log" # optional
36
-
37
- log_info = "/path/to/file_info.log" # optional
38
-
39
- round_ndigits = 6 # optional, default=5
40
-
41
- chain_id = 421613
42
-
43
- nodes = """
44
- https://arbitrum-goerli.publicnode.com
45
- https://rpc.goerli.arbitrum.gateway.fm
46
- """
@@ -1,37 +0,0 @@
1
- from rich.live import Live
2
- from rich.table import Table
3
-
4
- from mm_eth import erc20, rpc
5
- from mm_eth.utils import from_wei_str
6
-
7
-
8
- def print_balances(
9
- rpc_nodes: list[str],
10
- addresses: list[str],
11
- *,
12
- token_address: str | None = None,
13
- token_decimals: int | None = None,
14
- round_ndigits: int = 5,
15
- ) -> None:
16
- table = Table(title="balances")
17
- table.add_column("n")
18
- table.add_column("address")
19
- table.add_column("nonce")
20
- table.add_column("balance, eth")
21
- if token_address is not None and token_decimals is not None:
22
- table.add_column("token, t")
23
- with Live(table, refresh_per_second=0.5):
24
- for count, address in enumerate(addresses):
25
- nonce = str(rpc.eth_get_transaction_count(rpc_nodes, address, attempts=5).ok_or_err())
26
- balance = rpc.eth_get_balance(rpc_nodes, address, attempts=5).map_or_else(
27
- lambda err: err,
28
- lambda ok: from_wei_str(ok, "eth", round_ndigits),
29
- )
30
- row: list[str] = [str(count), address, nonce, balance]
31
- if token_address is not None and token_decimals is not None:
32
- erc20_balance = erc20.get_balance(rpc_nodes, token_address, address, attempts=5).map_or_else(
33
- lambda err: err,
34
- lambda ok: from_wei_str(ok, "t", decimals=token_decimals, round_ndigits=round_ndigits),
35
- )
36
- row.append(erc20_balance)
37
- table.add_row(*row)
mm_eth/constants.py DELETED
@@ -1 +0,0 @@
1
- SUFFIX_DECIMALS = {"eth": 18, "gwei": 9, "ether": 18}
mm_eth/ens.py DELETED
@@ -1,106 +0,0 @@
1
- from ens.utils import normal_name_to_hash
2
- from mm_crypto_utils import Nodes, Proxies, random_node, random_proxy
3
- from mm_std import Err, Ok, Result
4
- from web3 import Web3
5
-
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)
12
-
13
-
14
- def get_name_with_retries(
15
- rpc_urls: Nodes, address: str, retries: int, timeout: float = 5, proxies: Proxies = None
16
- ) -> Result[str | None]:
17
- res: Result[str | None] = Err("not started yet")
18
- for _ in range(retries):
19
- res = get_name(random_node(rpc_urls), address, timeout=timeout, proxy=random_proxy(proxies))
20
- if res.is_ok():
21
- return res
22
- return res
23
-
24
-
25
- def get_name(rpc_url: str, address: str, timeout: float = 5, proxy: str | None = None) -> Result[str | None]:
26
- try:
27
- w3 = get_w3(rpc_url, timeout=timeout, proxy=proxy)
28
- return Ok(w3.ens.name(w3.to_checksum_address(address))) # type: ignore[union-attr]
29
- except Exception as e:
30
- error = str(e)
31
- if not error:
32
- error = e.__class__.__qualname__
33
- return Err("exception: " + error)
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)
87
-
88
- try:
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"))
94
- except Exception as e:
95
- return Err(e)
96
-
97
-
98
- async def get_name_with_retries_async(
99
- rpc_urls: Nodes, address: str, retries: int, timeout: float = 5, proxies: Proxies = None
100
- ) -> Result[str | None]:
101
- res: Result[str | None] = Err("not started yet")
102
- for _ in range(retries):
103
- res = await get_name_async(random_node(rpc_urls), address, timeout=timeout, proxy=random_proxy(proxies))
104
- if res.is_ok():
105
- return res
106
- return res
mm_eth/ethernodes.py DELETED
@@ -1,34 +0,0 @@
1
- from datetime import datetime
2
-
3
- from mm_std import CHROME_USER_AGENT, Ok, Result, hr
4
- from pydantic import BaseModel, Field
5
-
6
-
7
- class SearchResult(BaseModel):
8
- class Node(BaseModel):
9
- id: str
10
- host: str
11
- port: int
12
- client: str
13
- client_version: str = Field(..., alias="clientVersion")
14
- os: str
15
- last_update: datetime = Field(..., alias="lastUpdate")
16
- country: str
17
- in_sync: int | None = Field(None, alias="inSync")
18
- isp: str
19
-
20
- draw: int
21
- records_total: int = Field(..., alias="recordsTotal")
22
- records_filtered: int = Field(..., alias="recordsFiltered")
23
- data: list[Node]
24
-
25
-
26
- def search_nodes(offset: int = 0, proxy: str | None = None) -> Result[SearchResult]:
27
- url = f"https://www.ethernodes.org/data?draw=1&columns%5B0%5D%5Bdata%5D=id&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=host&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=isp&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=country&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=client&columns%5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=true&columns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=clientVersion&columns%5B5%5D%5Bname%5D=&columns%5B5%5D%5Bsearchable%5D=true&columns%5B5%5D%5Borderable%5D=true&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B6%5D%5Bdata%5D=os&columns%5B6%5D%5Bname%5D=&columns%5B6%5D%5Bsearchable%5D=true&columns%5B6%5D%5Borderable%5D=true&columns%5B6%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B6%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B7%5D%5Bdata%5D=lastUpdate&columns%5B7%5D%5Bname%5D=&columns%5B7%5D%5Bsearchable%5D=true&columns%5B7%5D%5Borderable%5D=true&columns%5B7%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B7%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B8%5D%5Bdata%5D=inSync&columns%5B8%5D%5Bname%5D=&columns%5B8%5D%5Bsearchable%5D=true&columns%5B8%5D%5Borderable%5D=true&columns%5B8%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B8%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc&search%5Bvalue%5D=&search%5Bregex%5D=false&length=100&start={offset}"
28
- res = hr(url, proxy=proxy, user_agent=CHROME_USER_AGENT)
29
- if res.is_error():
30
- return res.to_err_result()
31
- try:
32
- return Ok(SearchResult(**res.json))
33
- except Exception as e:
34
- return res.to_err_result(f"exception: {e}")
mm_eth/json_encoder.py DELETED
@@ -1,15 +0,0 @@
1
- from hexbytes import HexBytes
2
- from mm_std import CustomJSONEncoder
3
-
4
-
5
- class EthJsonEncoder(CustomJSONEncoder):
6
- def default(self, o: object) -> object:
7
- if isinstance(o, HexBytes):
8
- return o.hex()
9
- return super().default(o)
10
-
11
-
12
- def json_default(o: object) -> str:
13
- if isinstance(o, HexBytes):
14
- return o.to_0x_hex()
15
- raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable")
mm_eth/rpc_async.py DELETED
@@ -1,160 +0,0 @@
1
- import json
2
- import string
3
- from collections.abc import Sequence
4
- from typing import Any
5
-
6
- import ens.utils
7
- import eth_utils
8
- import websockets
9
- from mm_std import DataResult, http_request
10
-
11
- DEFAULT_TIMEOUT = 7.0
12
-
13
-
14
- async def rpc_call(
15
- node: str,
16
- method: str,
17
- params: Sequence[object],
18
- timeout: float,
19
- proxy: str | None,
20
- id_: int = 1,
21
- ) -> DataResult[Any]:
22
- data = {"jsonrpc": "2.0", "method": method, "params": params, "id": id_}
23
- if node.startswith("http"):
24
- return await _http_call(node, data, timeout, proxy)
25
- return await _ws_call(node, data, timeout)
26
-
27
-
28
- async def _http_call(node: str, data: dict[str, object], timeout: float, proxy: str | None) -> DataResult[Any]:
29
- res = await http_request(node, method="POST", proxy=proxy, timeout=timeout, json=data)
30
- if res.is_error():
31
- return res.to_data_result_err()
32
- try:
33
- parsed_body = res.parse_json_body()
34
- err = parsed_body.get("error", {}).get("message", "")
35
- if err:
36
- return res.to_data_result_err(f"service_error: {err}")
37
- if "result" in parsed_body:
38
- return res.to_data_result_ok(parsed_body["result"])
39
- return res.to_data_result_err("unknown_response")
40
- except Exception as err:
41
- return res.to_data_result_err(f"exception: {err}")
42
-
43
-
44
- async def _ws_call(node: str, data: dict[str, object], timeout: float) -> DataResult[Any]:
45
- try:
46
- async with websockets.connect(node, timeout=timeout) as ws:
47
- await ws.send(json.dumps(data))
48
- response = json.loads(await ws.recv())
49
-
50
- err = response.get("error", {}).get("message", "")
51
- if err:
52
- return DataResult.err(f"service_error: {err}", response)
53
- if "result" in response:
54
- return DataResult.ok(response["result"], response)
55
- return DataResult.err("unknown_response", response)
56
- except TimeoutError:
57
- return DataResult.err("timeout")
58
- except Exception as err:
59
- return DataResult.exception(err)
60
-
61
-
62
- async def eth_block_number(node: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None) -> DataResult[int]:
63
- return (await rpc_call(node, "eth_blockNumber", [], timeout, proxy)).map(_hex_str_to_int)
64
-
65
-
66
- async def eth_get_balance(node: str, address: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None) -> DataResult[int]:
67
- return (await rpc_call(node, "eth_getBalance", [address, "latest"], timeout, proxy)).map(_hex_str_to_int)
68
-
69
-
70
- async def erc20_balance(
71
- node: str, token_address: str, user_address: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None
72
- ) -> DataResult[int]:
73
- data = "0x70a08231000000000000000000000000" + user_address[2:]
74
- params = [{"to": token_address, "data": data}, "latest"]
75
- return (await rpc_call(node, "eth_call", params, timeout, proxy)).map(_hex_str_to_int)
76
-
77
-
78
- async def erc20_name(
79
- node: str, token_address: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None
80
- ) -> DataResult[str]:
81
- params = [{"to": token_address, "data": "0x06fdde03"}, "latest"]
82
- return (await rpc_call(node, "eth_call", params, timeout, proxy)).map(_normalize_str)
83
-
84
-
85
- async def erc20_symbol(
86
- node: str, token_address: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None
87
- ) -> DataResult[str]:
88
- params = [{"to": token_address, "data": "0x95d89b41"}, "latest"]
89
- return (await rpc_call(node, "eth_call", params, timeout, proxy)).map(_normalize_str)
90
-
91
-
92
- async def erc20_decimals(
93
- node: str, token_address: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None
94
- ) -> DataResult[int]:
95
- params = [{"to": token_address, "data": "0x313ce567"}, "latest"]
96
- res = await rpc_call(node, "eth_call", params, timeout, proxy)
97
- if res.is_err():
98
- return res
99
- try:
100
- if res.unwrap() == "0x":
101
- return DataResult.err("no_decimals", res.data)
102
- value = res.unwrap()
103
- result = eth_utils.to_int(hexstr=value[0:66]) if len(value) > 66 else eth_utils.to_int(hexstr=value)
104
- return DataResult.ok(result, res.data)
105
- except Exception as err:
106
- return DataResult.exception(err, data=res.data)
107
-
108
-
109
- ENS_REGISTRY_ADDRESS: str = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
110
- FUNC_SELECTOR_RESOLVER: str = "0x0178b8bf" # resolver(bytes32)
111
- FUNC_SELECTOR_NAME: str = "0x691f3431" # name(bytes32)
112
-
113
-
114
- async def ens_name(node: str, address: str, timeout: float = DEFAULT_TIMEOUT, proxy: str | None = None) -> DataResult[str | None]:
115
- checksum_addr = eth_utils.to_checksum_address(address)
116
- reverse_name = checksum_addr.lower()[2:] + ".addr.reverse"
117
- name_hash_hex = ens.utils.normal_name_to_hash(reverse_name).hex()
118
-
119
- resolver_data = FUNC_SELECTOR_RESOLVER + name_hash_hex
120
-
121
- resolver_params = [{"to": ENS_REGISTRY_ADDRESS, "data": resolver_data}, "latest"]
122
-
123
- resolver_res = await rpc_call(node, method="eth_call", params=resolver_params, timeout=timeout, proxy=proxy)
124
- if resolver_res.is_err():
125
- return resolver_res
126
-
127
- if resolver_res.is_ok() and len(resolver_res.unwrap()) != 66:
128
- return DataResult.ok(None, {"revolver_response": resolver_res.dict()})
129
-
130
- resolver_address = eth_utils.to_checksum_address("0x" + resolver_res.unwrap()[-40:])
131
-
132
- name_data: str = FUNC_SELECTOR_NAME + name_hash_hex
133
- name_params = [{"to": resolver_address, "data": name_data}, "latest"]
134
-
135
- name_res: DataResult[str] = await rpc_call(node, "eth_call", name_params, timeout=timeout, proxy=proxy)
136
-
137
- if name_res.is_err():
138
- return DataResult.err(name_res.unwrap_err(), {"resolver_response": resolver_res.dict(), "name_response": name_res.dict()})
139
-
140
- if name_res.unwrap() == "0x":
141
- return DataResult.ok(None, {"resolver_response": resolver_res.dict(), "name_response": name_res.dict()})
142
-
143
- try:
144
- hex_data = name_res.unwrap()
145
- length_hex = hex_data[66:130]
146
- str_len = int(length_hex, 16) * 2
147
- name_hex = hex_data[130 : 130 + str_len]
148
- return DataResult.ok(
149
- bytes.fromhex(name_hex).decode("utf-8"), {"resolver_response": resolver_res.dict(), "name_response": name_res.dict()}
150
- )
151
- except Exception as err:
152
- return DataResult.exception(err, data={"resolver_response": resolver_res.dict(), "name_response": name_res.dict()})
153
-
154
-
155
- def _hex_str_to_int(value: str) -> int:
156
- return int(value, 16)
157
-
158
-
159
- def _normalize_str(value: str) -> str:
160
- return "".join(filter(lambda x: x in string.printable, eth_utils.to_text(hexstr=value))).strip()
mm_eth/vault.py DELETED
@@ -1,38 +0,0 @@
1
- from mm_std import Err, Ok, Result, hr
2
-
3
- from mm_eth.account import private_to_address
4
-
5
-
6
- def read_keys_from_vault(keys_url: str, token: str) -> Result[dict[str, str]]:
7
- data = None
8
- try:
9
- # keys_url example, https://vault.site.com:8200/v1/kv/keys1
10
- res = hr(keys_url, headers={"X-Vault-Token": token})
11
- data = res.json
12
- return Ok(res.json["data"], data=data)
13
- except Exception as e:
14
- return Err(f"exception: {e}", data=data)
15
-
16
-
17
- def set_keys_from_vault(keys_url: str, token: str, private_keys: list[str], verify_tls: bool = True) -> Result[bool]:
18
- """It works with KV version=1 only!!!"""
19
- # TODO: check that keys_url is kv1 version and error if it's kv2
20
- data = None
21
- try:
22
- # keys_url example, https://vault.site.com:8200/v1/kv/keys1
23
- keys: dict[str, str] = {}
24
- for private_key in private_keys:
25
- address = private_to_address(private_key)
26
- if address is None:
27
- return Err("wrong private key", data=data)
28
- keys[address] = private_key
29
-
30
- res = hr(keys_url, method="post", headers={"X-Vault-Token": token}, params=keys, verify=verify_tls)
31
- data = res.json
32
- if res.code == 204:
33
- return Ok(res.code == 204, data=data)
34
- if res.code == 403:
35
- return Err("permission denied", data=data)
36
- return Err(res.error or "error", data=data)
37
- except Exception as e:
38
- return Err(f"exception: {e}", data=data)
@@ -1,49 +0,0 @@
1
- mm_eth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_eth/abi.py,sha256=Qf-QOsR9QexyQM9XWKNeTMkRarIL3XQJbaDbJ8ifMrw,4856
3
- mm_eth/account.py,sha256=k0MNMatBe0zo1iKZiB_Tq6zyEIo22IncD6ewNUJp3dY,2075
4
- mm_eth/anvil.py,sha256=98RCfI7dEpxFBTV6UErYvubWVP3n0ctUFn1--4kZ84U,1603
5
- mm_eth/async_rpc.py,sha256=zjPcOoC-NTjMxbWu6cRQn-knHEQ75ZO5L-KZoaiwUJ0,2981
6
- mm_eth/constants.py,sha256=Cy_G-IleBH4gAZ4ok8AGHHlqmdW0ZM7ZldyVpzAfWLs,54
7
- mm_eth/deploy.py,sha256=SB3ruY808_5UnG8kHR34uVP66P3zOWZu0ImKD7UUv2s,691
8
- mm_eth/ens.py,sha256=lH3TZABYFBiEEtWlyxCqrcYC-nZQsI_1wSCMzBzHPrM,3860
9
- mm_eth/erc20.py,sha256=LZmTkjmXpN7sUhOtSLiTqb8Ubet9C9q32EQwTS78OqE,7378
10
- mm_eth/ethernodes.py,sha256=V4VVbC6Nr9jhwT7blxtLugXC5KfXqE8n-kP0VvGHbqo,3070
11
- mm_eth/json_encoder.py,sha256=S4oD-qfTVztMb4sRpY1puhBQwOBofTyQXWszmdXk4og,433
12
- mm_eth/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- mm_eth/rpc.py,sha256=k0eHxo_Dp6G0fHQ_rD-QbwOJz5ngC6kxBjl5NEHnyw8,13832
14
- mm_eth/rpc_async.py,sha256=PU19G9_tJSa4vfmaFUowjRCRy8dvfyJh9Lpkpe4FR4k,6462
15
- mm_eth/solc.py,sha256=dYRvT8PjZlLDZhNsc_-0790Eug_ZwU2G-iBfIdGj6wQ,1071
16
- mm_eth/tx.py,sha256=efSoMCoWkenbGdHo1_LX66_Edz1HvED5-J_i3wrHwMw,4051
17
- mm_eth/utils.py,sha256=FytG3U6h80mnUaKP8W2mPZ77EuOp4U7pVbPuoKI3wW4,8215
18
- mm_eth/vault.py,sha256=h8NyiOQh5YFskh1lZA3KyvnJUnxl9769ME2ChplG0CM,1477
19
- mm_eth/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- mm_eth/cli/calcs.py,sha256=cLFTYNAN-I53tUiSg-zFfVr2afjIZPftDDjHj16FBz0,1068
21
- mm_eth/cli/cli.py,sha256=yunHFL67-cEBXfogVgYzqLIhtjPIlyHtC6UNZdNg9Mw,9332
22
- mm_eth/cli/cli_utils.py,sha256=6TIGGEh3zGPTJQ6DKeOdz8JBg0XdL5gWt6WwppRThyk,1814
23
- mm_eth/cli/print_helpers.py,sha256=yOiOFjTKloumwf07AqNIHQswUo8t0yuT9bpeGBGl60Q,1470
24
- mm_eth/cli/rpc_helpers.py,sha256=FMV-QVNM3v9X8H_-DP0hjNRqmm7KOnfzkw9bP17Qbz0,4499
25
- mm_eth/cli/validators.py,sha256=KIAQUohl4_KKDvynbeqIeywtNnMWhTKYlnTdaxcjn6U,1690
26
- mm_eth/cli/cmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- mm_eth/cli/cmd/balance_cmd.py,sha256=aWJFteLnkgw9RqDsIV34a5_rh00fmFR9SXSJUtVyP3U,1856
28
- mm_eth/cli/cmd/balances_cmd.py,sha256=4UiWSNH9OCnkvcMGPTygEss8119do-rfG7QtsNMfWZs,4197
29
- mm_eth/cli/cmd/call_contract_cmd.py,sha256=RbBPvyUEQ45hQINYDKkx1yWhPygdymVKlRL26xI31uk,1264
30
- mm_eth/cli/cmd/deploy_cmd.py,sha256=0oBp_RZw_DIEtBFRc6QKdAw5oouwwpDIdeXvuyP9xdU,1272
31
- mm_eth/cli/cmd/encode_input_data_cmd.py,sha256=9UQ1MKPEFQJ8j_COsP3KGKhwOf9tT3feBezI8vvxTlw,267
32
- mm_eth/cli/cmd/example_cmd.py,sha256=QLipRKoR6T1my9qnMpzk2uPtj61mbwcuCMNFmyqRgJo,276
33
- mm_eth/cli/cmd/node_cmd.py,sha256=tFk4YECUUb-Rt_YIfMc_IGlqzxQjpsZmjp7OK2v0crI,2502
34
- mm_eth/cli/cmd/rpc_cmd.py,sha256=02q82YqgbPezfEBmV_QBCIeNReE7ktkPych8Xr9ann8,2186
35
- mm_eth/cli/cmd/solc_cmd.py,sha256=tBpeMdPfGs2iQIMaIJAAhMh1a3KyXHwyninfXPVpsgs,677
36
- mm_eth/cli/cmd/token_cmd.py,sha256=4y6ZQpLOJ33_iNuKpm9tZXh4RntWhmPUcizgaNNBzaw,1102
37
- mm_eth/cli/cmd/transfer_cmd.py,sha256=5Twb94GSZ0NiOj1PgY_1TdIHDoGN3Eq6qACelnCQPWQ,13298
38
- mm_eth/cli/cmd/tx_cmd.py,sha256=PIenXYTT60Z2fqsivpzybCLI2Z_tlcz-asm3B0JLHgI,517
39
- mm_eth/cli/cmd/vault_cmd.py,sha256=MOM1CILIaaqown1I-Fgo22ckqIMLtFt8t2D3fWNp798,606
40
- mm_eth/cli/cmd/wallet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- mm_eth/cli/cmd/wallet/mnemonic_cmd.py,sha256=xE-5Ux9BdYsTZYBy0dMn9jupGhW4ced-AgYscy_wU_4,1007
42
- mm_eth/cli/cmd/wallet/private_key_cmd.py,sha256=Fv_2OLog1h32pIP7PJITwl_pHdy3BXvaDRcXZsxY1xo,241
43
- mm_eth/cli/examples/balances.toml,sha256=i_ALpiEcf8-0TFiUg1cgJhxxfHYeBl9x0b3tnUWjswU,421
44
- mm_eth/cli/examples/call_contract.toml,sha256=ZQWK-409V_vLIZ2bsRD5RCWPPzShPz2KJTTRQY4YaGw,248
45
- mm_eth/cli/examples/transfer.toml,sha256=8mWuphDquoSDJw-hb9VJqtonjmv3kJ5Ip8jJ4t5YnfM,1810
46
- mm_eth-0.5.17.dist-info/METADATA,sha256=lWZylDIZ_1vZg3w6UCDqE7Dx-vvxRrJSPCnYUD9np2o,247
47
- mm_eth-0.5.17.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
- mm_eth-0.5.17.dist-info/entry_points.txt,sha256=aGhpsozl8NIrkuUcX5fSgURCcDhr3ShUdeTSIrJq4oc,46
49
- mm_eth-0.5.17.dist-info/RECORD,,