mm-eth 0.1.1__tar.gz → 0.1.3__tar.gz

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 (78) hide show
  1. mm_eth-0.1.3/.gitignore +14 -0
  2. mm_eth-0.1.3/PKG-INFO +9 -0
  3. mm_eth-0.1.3/justfile +36 -0
  4. {mm_eth-0.1.1 → mm_eth-0.1.3}/pyproject.toml +17 -10
  5. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/abi.py +5 -6
  6. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/account.py +6 -5
  7. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cli.py +1 -1
  8. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/tx.py +3 -3
  9. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/utils.py +4 -0
  10. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/zksync.py +2 -2
  11. mm_eth-0.1.3/tests/__init__.py +0 -0
  12. mm_eth-0.1.3/tests/cli/__init__.py +0 -0
  13. mm_eth-0.1.3/tests/cli/cmd/__init__.py +0 -0
  14. mm_eth-0.1.3/tests/cli/cmd/test_balance_cmd.py +11 -0
  15. mm_eth-0.1.3/tests/cli/cmd/test_mnemonic_cmd.py +10 -0
  16. mm_eth-0.1.3/tests/cli/cmd/test_node_cmd.py +10 -0
  17. mm_eth-0.1.3/tests/cli/cmd/test_private_key_cmd.py +8 -0
  18. mm_eth-0.1.3/tests/cli/cmd/test_solc_cmd.py +10 -0
  19. mm_eth-0.1.3/tests/cli/test_calcs.py +33 -0
  20. mm_eth-0.1.3/tests/conftest.py +110 -0
  21. mm_eth-0.1.3/tests/contracts/ERC20.sol +207 -0
  22. mm_eth-0.1.3/tests/contracts/abi/ERC20.json +72 -0
  23. mm_eth-0.1.3/uv.lock +1550 -0
  24. mm_eth-0.1.1/PKG-INFO +0 -9
  25. mm_eth-0.1.1/setup.cfg +0 -4
  26. mm_eth-0.1.1/src/mm_eth.egg-info/PKG-INFO +0 -9
  27. mm_eth-0.1.1/src/mm_eth.egg-info/SOURCES.txt +0 -60
  28. mm_eth-0.1.1/src/mm_eth.egg-info/dependency_links.txt +0 -1
  29. mm_eth-0.1.1/src/mm_eth.egg-info/entry_points.txt +0 -2
  30. mm_eth-0.1.1/src/mm_eth.egg-info/requires.txt +0 -5
  31. mm_eth-0.1.1/src/mm_eth.egg-info/top_level.txt +0 -1
  32. {mm_eth-0.1.1 → mm_eth-0.1.3}/README.txt +0 -0
  33. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/__init__.py +0 -0
  34. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/abi/zksync.json +0 -0
  35. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/anvil.py +0 -0
  36. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/__init__.py +0 -0
  37. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/calcs.py +0 -0
  38. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cli_helpers.py +0 -0
  39. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cli_utils.py +0 -0
  40. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/__init__.py +0 -0
  41. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/balance_cmd.py +0 -0
  42. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/balances_cmd.py +0 -0
  43. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/call_contract_cmd.py +0 -0
  44. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/config_example_cmd.py +0 -0
  45. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/deploy_cmd.py +0 -0
  46. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/encode_input_data_cmd.py +0 -0
  47. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/mnemonic_cmd.py +0 -0
  48. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/node_cmd.py +0 -0
  49. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/private_key_cmd.py +0 -0
  50. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/rpc_cmd.py +0 -0
  51. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/send_contract_cmd.py +0 -0
  52. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/solc_cmd.py +0 -0
  53. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/token_cmd.py +0 -0
  54. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/transfer_erc20_cmd.py +0 -0
  55. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/transfer_eth_cmd.py +0 -0
  56. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/cmd/vault_cmd.py +0 -0
  57. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/config_examples/balances.yml +0 -0
  58. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/config_examples/call_contract.yml +0 -0
  59. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/config_examples/transfer_erc20.yml +0 -0
  60. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/config_examples/transfer_eth.yml +0 -0
  61. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/cli/validators.py +0 -0
  62. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/deploy.py +0 -0
  63. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/ens.py +0 -0
  64. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/erc20.py +0 -0
  65. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/ethernodes.py +0 -0
  66. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/py.typed +0 -0
  67. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/rpc.py +0 -0
  68. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/services/__init__.py +0 -0
  69. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/solc.py +0 -0
  70. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/types.py +0 -0
  71. {mm_eth-0.1.1 → mm_eth-0.1.3}/src/mm_eth/vault.py +0 -0
  72. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_abi.py +0 -0
  73. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_account.py +0 -0
  74. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_ethernodes.py +0 -0
  75. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_rpc.py +0 -0
  76. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_tx.py +0 -0
  77. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_utils.py +0 -0
  78. {mm_eth-0.1.1 → mm_eth-0.1.3}/tests/test_zksync.py +0 -0
@@ -0,0 +1,14 @@
1
+ .idea
2
+ .venv
3
+ .env
4
+ .coverage
5
+ /htmlcov
6
+ __pycache__
7
+ *.egg-info
8
+ pip-wheel-metadata
9
+ .pytest_cache
10
+ .mypy_cache
11
+ .ruff_cache
12
+ /dist
13
+ /build
14
+ /tmp
mm_eth-0.1.3/PKG-INFO ADDED
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.3
2
+ Name: mm-eth
3
+ Version: 0.1.3
4
+ Requires-Python: >=3.12
5
+ Requires-Dist: loguru~=0.7.2
6
+ Requires-Dist: mm-std~=0.1.3
7
+ Requires-Dist: typer~=0.12.5
8
+ Requires-Dist: web3~=7.3.0
9
+ Requires-Dist: websocket-client~=1.8.0
mm_eth-0.1.3/justfile ADDED
@@ -0,0 +1,36 @@
1
+ set dotenv-load
2
+ version := `uv run python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])'`
3
+
4
+
5
+ clean:
6
+ rm -rf .pytest_cache .mypy_cache .ruff_cache .coverage dist build src/*.egg-info
7
+
8
+ build: clean lint audit test
9
+ uvx --from build pyproject-build --installer uv
10
+
11
+ format:
12
+ uv run ruff check --select I --fix src tests
13
+ uv run ruff format src tests
14
+
15
+ test:
16
+ uv run coverage run -m pytest -n auto tests
17
+
18
+ lint: format
19
+ uv run ruff check src tests
20
+ uv run mypy src
21
+
22
+ audit:
23
+ uv run pip-audit
24
+ uv run bandit -r -c "pyproject.toml" src
25
+
26
+ publish: build
27
+ git diff-index --quiet HEAD
28
+ uvx twine upload dist/**
29
+ git tag -a 'v{{version}}' -m 'v{{version}}'
30
+ git push origin v{{version}}
31
+
32
+ sync:
33
+ uv sync
34
+
35
+ anvil:
36
+ anvil -m "$MNEMONIC"
@@ -1,33 +1,37 @@
1
1
  [project]
2
2
  name = "mm-eth"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  description = ""
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
7
- "mm-std~=0.1.0",
7
+ "mm-std~=0.1.3",
8
8
  "websocket-client~=1.8.0",
9
- "web3~=6.20.0",
10
- "typer~=0.12.0",
9
+ "web3~=7.3.0",
10
+ "typer~=0.12.5",
11
11
  "loguru~=0.7.2",
12
12
  ]
13
13
  [project.scripts]
14
14
  mm-eth = "mm_eth.cli.cli:app"
15
15
 
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"
19
+
16
20
  [tool.uv]
17
21
  dev-dependencies = [
18
- "pytest~=8.3.2",
22
+ "pytest~=8.3.3",
19
23
  "pytest-xdist~=3.6.1",
20
24
  "pytest-httpserver~=1.1.0",
21
25
  "coverage~=7.6.0",
22
- "ruff~=0.6.1",
26
+ "ruff~=0.6.8",
23
27
  "pip-audit~=2.7.0",
24
- "bandit~=1.7.7",
25
- "mypy~=1.11.0",
26
- "types-python-dateutil~=2.9.0.20240821",
27
- "types-requests~=2.32.0.20240523",
28
+ "bandit~=1.7.10",
29
+ "mypy~=1.11.2",
30
+ "types-python-dateutil~=2.9.0.20240906",
28
31
  "types-PyYAML~=6.0.12.12",
29
32
  ]
30
33
 
34
+
31
35
  [tool.mypy]
32
36
  python_version = "3.12"
33
37
  mypy_path = "stubs"
@@ -68,3 +72,6 @@ lint.ignore = [
68
72
  [tool.bandit]
69
73
  exclude_dirs = ["tests"]
70
74
  skips = ["B311"]
75
+
76
+ [tool.pytest.ini_options]
77
+ markers = ["infura"]
@@ -6,11 +6,10 @@ from typing import Any, cast
6
6
  import eth_abi
7
7
  import eth_utils
8
8
  import pydash
9
- from eth_typing import HexStr
9
+ from eth_typing import ABI, ABIFunction, HexStr
10
10
  from pydantic import BaseModel
11
11
  from web3 import Web3
12
12
  from web3.auto import w3
13
- from web3.types import ABI, ABIFunction
14
13
 
15
14
  from mm_eth.utils import hex_to_bytes
16
15
 
@@ -85,7 +84,7 @@ def encode_function_input_by_abi(abi: ABI | ABIFunction, fn_name: str, args: lis
85
84
  else:
86
85
  processed_args.append(args[idx])
87
86
 
88
- return Web3().eth.contract(abi=[abi]).encodeABI(fn_name=fn_name, args=processed_args) # type: ignore[no-any-return]
87
+ return Web3().eth.contract(abi=[abi]).encode_abi(abi_element_identifier=fn_name, args=processed_args) # type: ignore[no-any-return]
89
88
 
90
89
 
91
90
  def encode_function_input_by_signature(func_signature: str, args: list[Any]) -> HexStr:
@@ -100,7 +99,7 @@ def encode_function_input_by_signature(func_signature: str, args: list[Any]) ->
100
99
  func_abi: ABIFunction = {
101
100
  "name": func_name,
102
101
  "type": "function",
103
- "inputs": [{"type": t} for t in arg_types],
102
+ "inputs": [{"type": t} for t in arg_types], # type: ignore[typeddict-item]
104
103
  }
105
104
  return encode_function_input_by_abi(func_abi, func_name, args)
106
105
 
@@ -123,8 +122,8 @@ def parse_function_signatures(contract_abi: ABI) -> dict[str, str]:
123
122
  result: dict[str, str] = {}
124
123
  for item in contract_abi:
125
124
  if item.get("type", None) == "function":
126
- function_name = item["name"]
127
- types = ",".join([i["type"] for i in item["inputs"]])
125
+ function_name = item["name"] # type: ignore
126
+ types = ",".join([i["type"] for i in item["inputs"]]) # type: ignore
128
127
  function_name_and_types = f"{function_name}({types})"
129
128
  result[function_name_and_types] = encode_function_signature(function_name_and_types)
130
129
  return result
@@ -7,7 +7,7 @@ from eth_keys import KeyAPI
7
7
  from eth_typing import ChecksumAddress
8
8
  from eth_utils import decode_hex
9
9
 
10
- Account.enable_unaudited_hdwallet_features() # type: ignore[no-untyped-call]
10
+ Account.enable_unaudited_hdwallet_features()
11
11
 
12
12
  key_api = KeyAPI()
13
13
 
@@ -24,7 +24,7 @@ def to_checksum_address(address: str) -> ChecksumAddress:
24
24
 
25
25
 
26
26
  def generate_mnemonic(num_words: int = 24) -> str:
27
- mnemonic = Mnemonic("english") # type: ignore[no-untyped-call]
27
+ mnemonic = Mnemonic("english")
28
28
  return mnemonic.generate(num_words=num_words)
29
29
 
30
30
 
@@ -38,13 +38,15 @@ def generate_accounts( # nosec
38
38
  for i in range(limit):
39
39
  path = f"{path_prefix}/{i}"
40
40
  acc = Account.from_mnemonic(mnemonic=mnemonic, account_path=path, passphrase=passphrase)
41
- result.append(NewAccount(path, acc.address, acc.key.hex()))
41
+ private_key = acc.key.hex().lower()
42
+ if not private_key.startswith("0x"):
43
+ private_key = f"0x{private_key}"
44
+ result.append(NewAccount(path, acc.address, private_key))
42
45
  return result
43
46
 
44
47
 
45
48
  def private_to_address(private_key: str) -> str | None:
46
49
  """returns address in lower case"""
47
- # noinspection PyBroadException
48
50
  try:
49
51
  return key_api.PrivateKey(decode_hex(private_key)).public_key.to_address().lower()
50
52
  except Exception:
@@ -62,7 +64,6 @@ def create_private_keys_dict(private_keys: list[str]) -> dict[str, str]: # addr
62
64
 
63
65
 
64
66
  def is_private_key(private_key: str) -> bool:
65
- # noinspection PyBroadException
66
67
  try:
67
68
  key_api.PrivateKey(decode_hex(private_key)).public_key.to_address()
68
69
  return True
@@ -61,7 +61,7 @@ def token_command(
61
61
  def node_command(
62
62
  urls: Annotated[list[str], typer.Argument()],
63
63
  print_format: Annotated[PrintFormat, typer.Option("--format", "-f", help="Print format")] = PrintFormat.TABLE,
64
- proxy: Annotated[str, typer.Option("--proxy", "-p", help="Proxy")] = "",
64
+ proxy: Annotated[str | None, typer.Option("--proxy", "-p", help="Proxy")] = None,
65
65
  ) -> None:
66
66
  node_cmd.run(urls, print_format, proxy)
67
67
 
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from typing import Any
4
4
 
5
5
  import rlp
6
- from eth_utils import keccak
6
+ from eth_utils import keccak, to_hex
7
7
  from pydantic import BaseModel
8
8
  from rlp.sedes import Binary, big_endian_int, binary
9
9
  from web3 import Web3
@@ -105,7 +105,7 @@ def sign_legacy_tx(
105
105
  tx["data"] = data
106
106
 
107
107
  signed = w3.eth.account.sign_transaction(tx, private_key)
108
- return SignedTx(tx_hash=signed.hash.hex(), raw_tx=signed.rawTransaction.hex())
108
+ return SignedTx(tx_hash=to_hex(signed.hash), raw_tx=to_hex(signed.raw_transaction))
109
109
 
110
110
 
111
111
  def sign_tx(
@@ -136,7 +136,7 @@ def sign_tx(
136
136
  tx["to"] = Web3.to_checksum_address(to)
137
137
 
138
138
  signed = w3.eth.account.sign_transaction(tx, private_key)
139
- return SignedTx(tx_hash=signed.hash.hex(), raw_tx=signed.rawTransaction.hex())
139
+ return SignedTx(tx_hash=signed.hash.hex(), raw_tx=signed.raw_transaction.hex())
140
140
 
141
141
 
142
142
  def decode_raw_tx(raw_tx: str) -> DecodedRawTx:
@@ -243,3 +243,7 @@ def random_node(nodes: Nodes, remove_slash: bool = True) -> str:
243
243
 
244
244
  def random_proxy(proxies: Proxies) -> str | None:
245
245
  return random_str_choice(proxies)
246
+
247
+
248
+ def to_hex(data: bytes | int | bool) -> str:
249
+ return Web3.to_hex(data)
@@ -2,12 +2,12 @@ import json
2
2
  import pkgutil
3
3
  from typing import cast
4
4
 
5
- from eth_typing import ChecksumAddress, HexStr
5
+ from eth_typing import ABI, ChecksumAddress, HexStr
6
6
  from hexbytes import HexBytes
7
7
  from mm_std import Err, Ok, Result
8
8
  from pydantic import BaseModel, Field
9
9
  from web3 import Web3
10
- from web3.types import ABI, Nonce, TxParams, Wei
10
+ from web3.types import Nonce, TxParams, Wei
11
11
 
12
12
  from mm_eth import abi, rpc
13
13
  from mm_eth.rpc import rpc_call
File without changes
File without changes
File without changes
@@ -0,0 +1,11 @@
1
+ import json
2
+
3
+ from mm_std import run_command
4
+
5
+
6
+ def test_eth_balance_cmd(anvil, address_1):
7
+ cmd = f"mm-eth balance {address_1} -u {anvil.rpc_url} -w -f json"
8
+ res = run_command(cmd)
9
+ assert res.code == 0
10
+ assert json.loads(res.stdout)["eth_balance"] == "10000000000000000000000"
11
+ assert json.loads(res.stdout)["nonce"] == 0
@@ -0,0 +1,10 @@
1
+ import json
2
+
3
+ from mm_std import run_command
4
+
5
+
6
+ def test_mnemonic_cmd(mnemonic, address_0, private_0):
7
+ cmd = f"mm-eth wallet mnemonic -m '{mnemonic}'"
8
+ res = run_command(cmd)
9
+ assert res.code == 0
10
+ assert json.loads(res.stdout)["accounts"][0] == {"address": address_0, "private": private_0}
@@ -0,0 +1,10 @@
1
+ import json
2
+
3
+ from mm_std import run_command
4
+
5
+
6
+ def test_node_cmd(anvil):
7
+ cmd = f"mm-eth node {anvil.rpc_url} -f json"
8
+ res = run_command(cmd)
9
+ assert res.code == 0
10
+ assert json.loads(res.stdout)[anvil.rpc_url]["chain_id"] == 31337
@@ -0,0 +1,8 @@
1
+ from mm_std import run_command
2
+
3
+
4
+ def test_private_key_cmd(private_0, address_0):
5
+ cmd = f"mm-eth wallet private-key {private_0}"
6
+ res = run_command(cmd)
7
+ assert res.code == 0
8
+ assert res.stdout.strip().lower() == address_0.lower()
@@ -0,0 +1,10 @@
1
+ import json
2
+
3
+ from mm_std import run_command
4
+
5
+
6
+ def test_solc_cmd():
7
+ cmd = "mm-eth solc tests/contracts/ERC20.sol -f json"
8
+ res = run_command(cmd)
9
+ assert res.code == 0
10
+ assert json.loads(res.stdout)["bin"].startswith("60806040")
@@ -0,0 +1,33 @@
1
+ import json
2
+
3
+ import pytest
4
+
5
+ from mm_eth.cli import calcs
6
+ from mm_eth.utils import to_wei
7
+
8
+
9
+ def test_calc_var_wei_value():
10
+ assert calcs.calc_var_wei_value("100") == 100
11
+ assert calcs.calc_var_wei_value("10 + 2 - 5") == 7
12
+ assert calcs.calc_var_wei_value("10 - random(2,2)") == 8
13
+ assert calcs.calc_var_wei_value("10gwei - random(2gwei,2gwei)") == to_wei("8gwei")
14
+ assert calcs.calc_var_wei_value("1.5base + 1", var_value=10, var_name="base") == 16
15
+ assert calcs.calc_var_wei_value("1.5estimate + 1", var_value=10, var_name="estimate") == 16
16
+ assert calcs.calc_var_wei_value("12.2 gwei") == to_wei("12.2gwei")
17
+ assert calcs.calc_var_wei_value("12.2 eth") == to_wei("12.2eth")
18
+ assert calcs.calc_var_wei_value("12.2 ether") == to_wei("12.2eth")
19
+ assert calcs.calc_var_wei_value("12.2 t", decimals=6) == 12.2 * 10**6
20
+
21
+ with pytest.raises(ValueError):
22
+ calcs.calc_var_wei_value("fff")
23
+ with pytest.raises(ValueError):
24
+ calcs.calc_var_wei_value("12.3 gwei + base", var_name="base")
25
+ with pytest.raises(ValueError):
26
+ calcs.calc_var_wei_value("1.5estimate + 1", var_value=10)
27
+ with pytest.raises(ValueError):
28
+ calcs.calc_var_wei_value("1.1t")
29
+
30
+
31
+ def test_calc_function_args():
32
+ res = calcs.calc_function_args('["xxx", random(100,200), 100, "aaa", random(1,3)]')
33
+ assert json.loads(res)[1] >= 100
@@ -0,0 +1,110 @@
1
+ import json
2
+
3
+ import pytest
4
+ from eth_typing import ABI
5
+ from mm_std import Err, get_dotenv
6
+
7
+ from mm_eth.anvil import Anvil
8
+
9
+
10
+ @pytest.fixture()
11
+ def mnemonic() -> str:
12
+ return "diet render mix evil relax apology hazard bamboo desert sign fence usage baby athlete cannon season busy ten jaguar silk rebel identify foster shrimp" # noqa
13
+
14
+
15
+ @pytest.fixture()
16
+ def erc20_token_abi_str() -> str:
17
+ return r'[{"inputs":[{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]' # noqa
18
+
19
+
20
+ @pytest.fixture()
21
+ def erc20_abi(erc20_token_abi_str) -> ABI:
22
+ return json.loads(erc20_token_abi_str)
23
+
24
+
25
+ @pytest.fixture()
26
+ def erc20_token_bin() -> str:
27
+ return "608060405234801562000010575f80fd5b5060405162000d1338038062000d138339810160408190526200003391620001dc565b60036200004183826200033b565b5060046200005083826200033b565b506005805460ff191660121790556200006a338262000072565b505062000423565b6001600160a01b038216620000ce5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064015b60405180910390fd5b600254620000dd90826200015d565b6002556001600160a01b0382165f908152602081905260409020546200010490826200015d565b6001600160a01b0383165f81815260208181526040808320949094559251848152919290917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b505050565b5f806200016b838562000403565b905083811015620001bf5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401620000c5565b90505b92915050565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215620001ee575f80fd5b82516001600160401b038082111562000205575f80fd5b818501915085601f83011262000219575f80fd5b8151818111156200022e576200022e620001c8565b604051601f8201601f19908116603f01168101908382118183101715620002595762000259620001c8565b8160405282815260209350888484870101111562000275575f80fd5b5f91505b8282101562000298578482018401518183018501529083019062000279565b5f928101840192909252509401519395939450505050565b600181811c90821680620002c557607f821691505b602082108103620002e457634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000158575f81815260208120601f850160051c81016020861015620003125750805b601f850160051c820191505b8181101562000333578281556001016200031e565b505050505050565b81516001600160401b03811115620003575762000357620001c8565b6200036f81620003688454620002b0565b84620002ea565b602080601f831160018114620003a5575f84156200038d5750858301515b5f19600386901b1c1916600185901b17855562000333565b5f85815260208120601f198616915b82811015620003d557888601518255948401946001909101908401620003b4565b5085821015620003f357878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b80820180821115620001c257634e487b7160e01b5f52601160045260245ffd5b6108e280620004315f395ff3fe608060405234801561000f575f80fd5b50600436106100a6575f3560e01c8063395093511161006e578063395093511461012557806370a082311461013857806395d89b4114610160578063a457c2d714610168578063a9059cbb1461017b578063dd62ed3e1461018e575f80fd5b806306fdde03146100aa578063095ea7b3146100c857806318160ddd146100eb57806323b872dd146100fd578063313ce56714610110575b5f80fd5b6100b26101c6565b6040516100bf91906106b6565b60405180910390f35b6100db6100d636600461071c565b610256565b60405190151581526020016100bf565b6002545b6040519081526020016100bf565b6100db61010b366004610744565b61026c565b60055460405160ff90911681526020016100bf565b6100db61013336600461071c565b6102d3565b6100ef61014636600461077d565b6001600160a01b03165f9081526020819052604090205490565b6100b2610308565b6100db61017636600461071c565b610317565b6100db61018936600461071c565b610364565b6100ef61019c366004610796565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6060600380546101d5906107c7565b80601f0160208091040260200160405190810160405280929190818152602001828054610201906107c7565b801561024c5780601f106102235761010080835404028352916020019161024c565b820191905f5260205f20905b81548152906001019060200180831161022f57829003601f168201915b5050505050905090565b5f610262338484610370565b5060015b92915050565b5f610278848484610499565b6102c984336102c485604051806060016040528060288152602001610860602891396001600160a01b038a165f9081526001602090815260408083203384529091529020549190610619565b610370565b5060019392505050565b335f8181526001602090815260408083206001600160a01b038716845290915281205490916102629185906102c49086610651565b6060600480546101d5906107c7565b5f61026233846102c48560405180606001604052806025815260200161088860259139335f9081526001602090815260408083206001600160a01b038d1684529091529020549190610619565b5f610262338484610499565b6001600160a01b0383166103d75760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b0382166104385760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016103ce565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b0383166104fd5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016103ce565b6001600160a01b03821661055f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016103ce565b61059b8160405180606001604052806026815260200161083a602691396001600160a01b0386165f908152602081905260409020549190610619565b6001600160a01b038085165f9081526020819052604080822093909355908416815220546105c99082610651565b6001600160a01b038381165f818152602081815260409182902094909455518481529092918616917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161048c565b5f818484111561063c5760405162461bcd60e51b81526004016103ce91906106b6565b505f6106488486610813565b95945050505050565b5f8061065d8385610826565b9050838110156106af5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f77000000000060448201526064016103ce565b9392505050565b5f6020808352835180828501525f5b818110156106e1578581018301518582016040015282016106c5565b505f604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610717575f80fd5b919050565b5f806040838503121561072d575f80fd5b61073683610701565b946020939093013593505050565b5f805f60608486031215610756575f80fd5b61075f84610701565b925061076d60208501610701565b9150604084013590509250925092565b5f6020828403121561078d575f80fd5b6106af82610701565b5f80604083850312156107a7575f80fd5b6107b083610701565b91506107be60208401610701565b90509250929050565b600181811c908216806107db57607f821691505b6020821081036107f957634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610266576102666107ff565b80820180821115610266576102666107ff56fe45524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220fdf5850518272abc852e84db2b1c5e730e5de114aa27c25a2f3447b021fb005064736f6c63430008140033" # noqa
28
+
29
+
30
+ @pytest.fixture()
31
+ def anvil(mnemonic):
32
+ res = Anvil.launch(mnemonic=mnemonic)
33
+ if isinstance(res, Err):
34
+ raise Exception(f"can't start anvil: {res.err}")
35
+ a = res.ok
36
+ try:
37
+ yield a
38
+ finally:
39
+ a.stop()
40
+
41
+
42
+ @pytest.fixture
43
+ def etherscan_key():
44
+ return get_dotenv("MM_PROXIES_APP")
45
+
46
+
47
+ @pytest.fixture
48
+ def mm_proxies() -> list[str]:
49
+ # url, token = get_dotenv("MM_PROXIES_APP").split("|")
50
+ # res = hr(f"{url}/api/proxies/live", headers={"access-token": token})
51
+ # return res.json.get("proxies")
52
+ return []
53
+
54
+
55
+ @pytest.fixture
56
+ def infura():
57
+ infura = get_dotenv("INFURA_API_KEY")
58
+
59
+ def _infura(network="mainnet", ws=False):
60
+ if ws:
61
+ return f"wss://{network}.infura.io/ws/v3/{infura}"
62
+ else:
63
+ return f"https://{network}.infura.io/v3/{infura}"
64
+
65
+ return _infura
66
+
67
+
68
+ @pytest.fixture
69
+ def mainnet_archive_node():
70
+ return get_dotenv("MAINNET_ARCHIVE_NODE")
71
+
72
+
73
+ @pytest.fixture
74
+ def address_bnb():
75
+ return "0xB8c77482e45F1F44dE1745F52C74426C631bDD52"
76
+
77
+
78
+ @pytest.fixture
79
+ def address_tether():
80
+ return "0xdac17f958d2ee523a2206206994597c13d831ec7"
81
+
82
+
83
+ @pytest.fixture
84
+ def address_0():
85
+ return "0x10fd602Bff689e64D4720D1DCCCD3494f1f16623"
86
+
87
+
88
+ @pytest.fixture
89
+ def private_0():
90
+ return "0x7bb5b9c0ba991275f84b796b4d25fd3a8d7320911f50fade85410e7a2b000632"
91
+
92
+
93
+ @pytest.fixture
94
+ def address_1():
95
+ return "0x58487485c3858109f5A37e42546FE87473f79a4b"
96
+
97
+
98
+ @pytest.fixture
99
+ def private_1():
100
+ return "0xe4d16faffffa9b28adf02fb5f06998d174046c369d2daffe9a750fbe6a333417"
101
+
102
+
103
+ @pytest.fixture
104
+ def address_2():
105
+ return "0x97C77B548aE0d4925F5C201220fC6d8996424309"
106
+
107
+
108
+ @pytest.fixture
109
+ def private_2():
110
+ return "0xb7e0b671e176b04ceb0897a698d34771bfe9acf29273dc52a141be6e97145a00"