mm-eth 0.2.0__py3-none-any.whl → 0.2.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.
mm_eth/abi.py CHANGED
@@ -64,7 +64,7 @@ def decode_function_input(contract_abi: ABI, tx_input: str) -> FunctionInput:
64
64
 
65
65
 
66
66
  def get_function_abi(contr_abi: ABI, fn_name: str) -> ABIFunction:
67
- abi = pydash.find(contr_abi, lambda x: x.get("name", None) == fn_name and x.get("type", None) == "function") # type:ignore
67
+ abi = pydash.find(contr_abi, lambda x: x.get("name", None) == fn_name and x.get("type", None) == "function") # type: ignore[call-overload, attr-defined]
68
68
  if not abi:
69
69
  raise ValueError("can't find abi for function: " + fn_name)
70
70
  return cast(ABIFunction, abi)
@@ -122,8 +122,8 @@ def parse_function_signatures(contract_abi: ABI) -> dict[str, str]:
122
122
  result: dict[str, str] = {}
123
123
  for item in contract_abi:
124
124
  if item.get("type", None) == "function":
125
- function_name = item["name"] # type: ignore
126
- types = ",".join([i["type"] for i in item["inputs"]]) # type: ignore
125
+ function_name = item["name"] # type: ignore[typeddict-item]
126
+ types = ",".join([i["type"] for i in item["inputs"]]) # type: ignore[typeddict-item]
127
127
  function_name_and_types = f"{function_name}({types})"
128
128
  result[function_name_and_types] = encode_function_signature(function_name_and_types)
129
129
  return result
mm_eth/account.py CHANGED
@@ -67,6 +67,6 @@ def create_private_keys_dict(private_keys: list[str]) -> dict[str, str]: # addr
67
67
  def is_private_key(private_key: str) -> bool:
68
68
  try:
69
69
  key_api.PrivateKey(decode_hex(private_key)).public_key.to_address()
70
- return True
70
+ return True # noqa: TRY300
71
71
  except Exception:
72
72
  return False
mm_eth/anvil.py CHANGED
@@ -10,7 +10,7 @@ from mm_eth import account, rpc
10
10
 
11
11
 
12
12
  class Anvil:
13
- def __init__(self, *, chain_id: int, port: int, mnemonic: str):
13
+ def __init__(self, *, chain_id: int, port: int, mnemonic: str) -> None:
14
14
  self.chain_id = chain_id
15
15
  self.port = port
16
16
  self.mnemonic = mnemonic
@@ -18,7 +18,7 @@ class Anvil:
18
18
 
19
19
  def start_process(self) -> None:
20
20
  cmd = f"anvil -m '{self.mnemonic}' -p {self.port} --chain-id {self.chain_id}"
21
- self.process = Popen(cmd, shell=True) # nosec
21
+ self.process = Popen(cmd, shell=True) # noqa: S602 # nosec
22
22
  time.sleep(3)
23
23
 
24
24
  def stop(self) -> None:
mm_eth/erc20.py CHANGED
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import string
4
- from collections.abc import Sequence
5
4
  from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  import eth_abi
8
8
  import eth_utils
@@ -11,11 +11,15 @@ from eth_utils import to_checksum_address, to_hex
11
11
  from mm_std import Err, Ok, Result
12
12
 
13
13
  from mm_eth import rpc
14
- from mm_eth.rpc import Log
15
14
  from mm_eth.tx import SignedTx, sign_legacy_tx, sign_tx
16
- from mm_eth.types import Nodes, Proxies
17
15
  from mm_eth.utils import hex_str_to_int, hex_to_bytes, log_topic_to_address
18
16
 
17
+ if TYPE_CHECKING:
18
+ from collections.abc import Sequence
19
+
20
+ from mm_eth.rpc import Log
21
+ from mm_eth.types import Nodes, Proxies
22
+
19
23
  TRANSFER_METHOD = "0xa9059cbb"
20
24
  TRANSFER_TOPIC = HexStr("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
21
25
 
@@ -108,10 +112,7 @@ def get_decimals(rpc_urls: Nodes, address: str, timeout: int = 10, proxies: Prox
108
112
  if res.ok == "0x":
109
113
  return Err("no_decimals", data=res.data)
110
114
 
111
- if len(res.ok) > 66:
112
- result = eth_utils.to_int(hexstr=res.ok[0:66])
113
- else:
114
- result = eth_utils.to_int(hexstr=res.ok)
115
+ result = eth_utils.to_int(hexstr=res.ok[0:66]) if len(res.ok) > 66 else eth_utils.to_int(hexstr=res.ok)
115
116
  return Ok(result, data=res.data)
116
117
 
117
118
  except Exception as e:
mm_eth/rpc.py CHANGED
@@ -2,16 +2,19 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  from dataclasses import dataclass
5
- from typing import Any, Literal, cast
5
+ from typing import TYPE_CHECKING, Any, Literal, cast
6
6
 
7
7
  import websocket
8
8
  from mm_std import Err, Ok, Result, hr, random_choice
9
9
  from pydantic import BaseModel
10
- from web3.types import BlockIdentifier
11
10
 
12
- from mm_eth.types import Nodes, Proxies
13
11
  from mm_eth.utils import hex_str_to_int, random_node, random_proxy
14
12
 
13
+ if TYPE_CHECKING:
14
+ from web3.types import BlockIdentifier
15
+
16
+ from mm_eth.types import Nodes, Proxies
17
+
15
18
 
16
19
  @dataclass
17
20
  class TxReceipt:
@@ -85,10 +88,7 @@ def rpc_call(
85
88
  res: Result[Any] = Err("not started yet")
86
89
  for _ in range(attempts):
87
90
  node = random_node(nodes)
88
- if node.startswith("http"):
89
- res = _http_call(node, data, timeout, random_proxy(proxies))
90
- else:
91
- res = _ws_call(node, data, timeout)
91
+ res = _http_call(node, data, timeout, random_proxy(proxies)) if node.startswith("http") else _ws_call(node, data, timeout)
92
92
  if isinstance(res, Ok):
93
93
  return res
94
94
  return res
@@ -444,7 +444,7 @@ def eth_syncing(rpc_urls: Nodes, timeout: int = 10, proxies: Proxies = None, att
444
444
  result[k] = int(v, 16)
445
445
  else:
446
446
  result[k] = v
447
- if result.get("currentBlock", None) and result.get("highestBlock", None):
447
+ if result.get("currentBlock") and result.get("highestBlock"):
448
448
  result["remaining"] = result["highestBlock"] - result["currentBlock"]
449
449
  return Ok(result, res.data)
450
450
 
mm_eth/solc.py CHANGED
@@ -1,4 +1,3 @@
1
- import os.path
2
1
  import random
3
2
  import shutil
4
3
  from dataclasses import dataclass
@@ -15,9 +14,9 @@ class SolcResult:
15
14
 
16
15
  def solc(contract_name: str, contract_path: str, tmp_dir: str) -> Result[SolcResult]:
17
16
  if tmp_dir.startswith("~"):
18
- tmp_dir = os.path.expanduser(tmp_dir)
17
+ tmp_dir = Path(tmp_dir).expanduser().as_posix()
19
18
  if contract_path.startswith("~"):
20
- contract_path = os.path.expanduser(contract_path)
19
+ contract_path = Path(contract_path).expanduser().as_posix()
21
20
  work_dir = f"{tmp_dir}/solc_{contract_name}_{random.randint(0, 100_000_000)}"
22
21
  abi_path = f"{work_dir}/{contract_name}.abi"
23
22
  bin_path = f"{work_dir}/{contract_name}.bin"
mm_eth/tx.py CHANGED
@@ -44,14 +44,12 @@ class RPLTransaction(rlp.Serializable): # type: ignore[misc]
44
44
  to: str | None = None,
45
45
  ) -> RPLTransaction:
46
46
  if to:
47
- to = hex_to_bytes(to) # type:ignore
47
+ to = hex_to_bytes(to) # type: ignore[assignment]
48
48
  if data:
49
- data = hex_to_bytes(data) # type:ignore
49
+ data = hex_to_bytes(data) # type: ignore[assignment]
50
50
  if not value:
51
51
  value = 0
52
- r = int(r, 16) # type:ignore
53
- s = int(s, 16) # type:ignore
54
- return RPLTransaction(nonce, gas_price, gas, to, value, data, v, r, s)
52
+ return RPLTransaction(nonce, gas_price, gas, to, value, data, v, int(r, 16), int(s, 16))
55
53
 
56
54
 
57
55
  class DecodedRawTx(BaseModel):
mm_eth/utils.py CHANGED
@@ -16,23 +16,22 @@ from mm_eth.types import Nodes, Proxies
16
16
 
17
17
 
18
18
  def parse_addresses(data: str) -> list[str]:
19
- data = data.lower()
20
19
  result = []
21
- for word in data.split():
20
+ for word in data.lower().split():
22
21
  if len(word) == 42 and re.match("0x[a-f0-9]{40}", word):
23
- result.append(word)
22
+ result.append(word) # noqa: PERF401
24
23
  return pydash.uniq(result)
25
24
 
26
25
 
27
26
  def to_token_wei(value: str | int, decimals: int) -> int:
28
27
  if isinstance(value, int):
29
28
  return value
30
- elif isinstance(value, str):
29
+ if isinstance(value, str):
31
30
  value = value.lower().replace(" ", "").strip()
32
31
  if value.endswith("t"):
33
32
  value = value.replace("t", "")
34
33
  return int(Decimal(value) * 10**decimals)
35
- elif value.isdigit():
34
+ if value.isdigit():
36
35
  return int(value)
37
36
 
38
37
  raise ValueError("wrong value" + value)
@@ -41,11 +40,11 @@ def to_token_wei(value: str | int, decimals: int) -> int:
41
40
  def to_wei(value: str | int | Decimal, decimals: int | None = None) -> Wei:
42
41
  if isinstance(value, int):
43
42
  return Wei(value)
44
- elif isinstance(value, Decimal):
43
+ if isinstance(value, Decimal):
45
44
  if value != value.to_integral_value():
46
45
  raise ValueError(f"value must be integral number: {value}")
47
46
  return Wei(int(value))
48
- elif isinstance(value, str):
47
+ if isinstance(value, str):
49
48
  value = value.lower().replace(" ", "").strip()
50
49
  if value.endswith("navax"): # https://snowtrace.io/unitconverter
51
50
  value = value.replace("navax", "")
@@ -68,8 +67,7 @@ def to_wei(value: str | int | Decimal, decimals: int | None = None) -> Wei:
68
67
  return Wei(int(value))
69
68
  raise ValueError("wrong value " + value)
70
69
 
71
- else:
72
- raise ValueError(f"value has a wrong type: {type(value)}")
70
+ raise ValueError(f"value has a wrong type: {type(value)}")
73
71
 
74
72
 
75
73
  def from_wei(
@@ -125,11 +123,11 @@ def from_token_wei_str(value: int, decimals: int, symbol: str = "", round_ndigit
125
123
  def to_wei_token(value: str | int | Decimal, symbol: str, decimals: int) -> int:
126
124
  if isinstance(value, int):
127
125
  return value
128
- elif isinstance(value, Decimal):
126
+ if isinstance(value, Decimal):
129
127
  if value != value.to_integral_value():
130
128
  raise ValueError(f"value must be integral number: {value}")
131
129
  return int(value)
132
- elif isinstance(value, str):
130
+ if isinstance(value, str):
133
131
  value = value.lower().replace(" ", "").strip()
134
132
  if value.isdigit():
135
133
  return int(value)
@@ -138,7 +136,7 @@ def to_wei_token(value: str | int | Decimal, symbol: str, decimals: int) -> int:
138
136
  except Exception as e:
139
137
  raise ValueError from e
140
138
  else:
141
- raise ValueError(f"value has a wrong type: {type(value)}")
139
+ raise TypeError(f"value has a wrong type: {type(value)}")
142
140
 
143
141
 
144
142
  def to_checksum_address(address: str) -> str:
@@ -185,10 +183,7 @@ def truncate_hex_str(hex_str: str, digits: int = 4, replace_str: str = "...") ->
185
183
 
186
184
 
187
185
  def log_topic_to_address(topic: HexBytes | str) -> str:
188
- if isinstance(topic, HexBytes):
189
- result = topic.hex()[-40:]
190
- else:
191
- result = topic[-40:]
186
+ result = topic.hex()[-40:] if isinstance(topic, HexBytes) else topic[-40:]
192
187
  if not result.startswith("0x"):
193
188
  result = f"0x{result}"
194
189
  return result
mm_eth/vault.py CHANGED
@@ -15,7 +15,8 @@ def read_keys_from_vault(keys_url: str, token: str) -> Result[dict[str, str]]:
15
15
 
16
16
 
17
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!!!""" # TODO: check that keys_url is kv1 version and error if it's kv2
18
+ """It works with KV version=1 only!!!"""
19
+ # TODO: check that keys_url is kv1 version and error if it's kv2
19
20
  data = None
20
21
  try:
21
22
  # keys_url example, https://vault.site.com:8200/v1/kv/keys1
@@ -23,16 +24,15 @@ def set_keys_from_vault(keys_url: str, token: str, private_keys: list[str], veri
23
24
  for private_key in private_keys:
24
25
  address = private_to_address(private_key)
25
26
  if address is None:
26
- raise ValueError("there is a wrong private key")
27
+ return Err("wrong private key", data=data)
27
28
  keys[address] = private_key
28
29
 
29
30
  res = hr(keys_url, method="post", headers={"X-Vault-Token": token}, params=keys, verify=verify_tls)
30
31
  data = res.json
31
32
  if res.code == 204:
32
33
  return Ok(res.code == 204, data=data)
33
- elif res.code == 403:
34
+ if res.code == 403:
34
35
  return Err("permission denied", data=data)
35
- else:
36
- return Err(res.error or "error", data=data)
36
+ return Err(res.error or "error", data=data)
37
37
  except Exception as e:
38
38
  return Err(f"exception: {e}", data=data)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-eth
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Requires-Python: >=3.12
5
- Requires-Dist: mm-std~=0.1.9
6
- Requires-Dist: web3~=7.6.1
5
+ Requires-Dist: mm-std~=0.1.10
6
+ Requires-Dist: web3~=7.7.0
7
7
  Requires-Dist: websocket-client~=1.8.0
@@ -0,0 +1,18 @@
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=IsajQ7156-CxqRFt2ntv_3nJKwi6tCZz0TmtjUCgmIg,2038
4
+ mm_eth/anvil.py,sha256=98RCfI7dEpxFBTV6UErYvubWVP3n0ctUFn1--4kZ84U,1603
5
+ mm_eth/deploy.py,sha256=SB3ruY808_5UnG8kHR34uVP66P3zOWZu0ImKD7UUv2s,691
6
+ mm_eth/ens.py,sha256=WMxqC1v3zwDDuLH_oWekm22qrNYxCNcvZumQMT7SYds,623
7
+ mm_eth/erc20.py,sha256=m0_yYzPYgOBx0oh4V330XGjRQBjMd5XlWhRL5qChvQE,6866
8
+ mm_eth/ethernodes.py,sha256=9y_poTmFUj6cnWaT9mtfc6S9lAfVXTwLGRqxMQ8hT0Y,3080
9
+ mm_eth/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ mm_eth/rpc.py,sha256=F0jBzYw4wkh9LKwynXrzyhA08r5JTGrYAbwTH6C2Z7w,13872
11
+ mm_eth/solc.py,sha256=dYRvT8PjZlLDZhNsc_-0790Eug_ZwU2G-iBfIdGj6wQ,1071
12
+ mm_eth/tx.py,sha256=J5Wky8rmV6NlMFmAYF4997PscRYlUdkYFpEldH3BCNg,4014
13
+ mm_eth/types.py,sha256=vXXP5Dc72BpHv5tsyws0KDZebG1W1-5HH0UjL7N2Mgc,113
14
+ mm_eth/utils.py,sha256=NICgROKU5ZTrkY6nlSDLHjbbpYYswLoofyc3ozPdwBs,7804
15
+ mm_eth/vault.py,sha256=h8NyiOQh5YFskh1lZA3KyvnJUnxl9769ME2ChplG0CM,1477
16
+ mm_eth-0.2.1.dist-info/METADATA,sha256=VZ2A_K7tjKAWxIzkq6K3zk3PQv6hXDRs89oBvGgApB0,170
17
+ mm_eth-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
+ mm_eth-0.2.1.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- mm_eth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_eth/abi.py,sha256=_xw2c7Eht3-g-fA6yvakHMcehzsRRK_LqTO7Q8Ppkj4,4794
3
- mm_eth/account.py,sha256=6iiCZ70ojptiaDI1UMaUdJT-SghuOexLeH0YJhCWQ8g,2022
4
- mm_eth/anvil.py,sha256=9CWXWyK7tVrvs6NeOy7QnVwMTrUke-nBMFwZeJ4VULA,1582
5
- mm_eth/deploy.py,sha256=SB3ruY808_5UnG8kHR34uVP66P3zOWZu0ImKD7UUv2s,691
6
- mm_eth/ens.py,sha256=WMxqC1v3zwDDuLH_oWekm22qrNYxCNcvZumQMT7SYds,623
7
- mm_eth/erc20.py,sha256=m62j00zizSZzXgLUEih2Q1iVFehU9qrqOMfc3gyix7k,6844
8
- mm_eth/ethernodes.py,sha256=9y_poTmFUj6cnWaT9mtfc6S9lAfVXTwLGRqxMQ8hT0Y,3080
9
- mm_eth/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- mm_eth/rpc.py,sha256=kQnYllp5ZHGuIUUX2Vw-ejLwL3zXQgka3ukwDndv4AM,13881
11
- mm_eth/solc.py,sha256=JcBCel-LO-lBvz3_1f7s3pVhECsUittavBvXqxYIP2c,1066
12
- mm_eth/tx.py,sha256=qSkaPgow3QEZR0vbnQouw8X4G-Hw9RedPrDB10aZhU0,4046
13
- mm_eth/types.py,sha256=vXXP5Dc72BpHv5tsyws0KDZebG1W1-5HH0UjL7N2Mgc,113
14
- mm_eth/utils.py,sha256=kjCIsXtRTG0dL6A1bCCuWctqd0Qh8K8N-ZocQRppYj0,7861
15
- mm_eth/vault.py,sha256=1ahABcgyYAMUlE4ELMGdlG_uV4irmwzrfzUZTpo3rdY,1500
16
- mm_eth-0.2.0.dist-info/METADATA,sha256=J5m9XoyV6IPyS5YDrRpTmzTFR_pnEESJXJhuhzeAHB8,169
17
- mm_eth-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
18
- mm_eth-0.2.0.dist-info/RECORD,,
File without changes