mm-eth 0.1.1__tar.gz → 0.1.2__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.
- mm_eth-0.1.2/.gitignore +14 -0
- mm_eth-0.1.2/PKG-INFO +9 -0
- mm_eth-0.1.2/justfile +37 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/pyproject.toml +15 -9
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/abi.py +5 -6
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/account.py +6 -5
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cli.py +1 -1
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/tx.py +3 -3
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/utils.py +4 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/zksync.py +2 -2
- mm_eth-0.1.2/tests/__init__.py +0 -0
- mm_eth-0.1.2/tests/cli/__init__.py +0 -0
- mm_eth-0.1.2/tests/cli/cmd/__init__.py +0 -0
- mm_eth-0.1.2/tests/cli/cmd/test_balance_cmd.py +11 -0
- mm_eth-0.1.2/tests/cli/cmd/test_mnemonic_cmd.py +10 -0
- mm_eth-0.1.2/tests/cli/cmd/test_node_cmd.py +10 -0
- mm_eth-0.1.2/tests/cli/cmd/test_private_key_cmd.py +8 -0
- mm_eth-0.1.2/tests/cli/cmd/test_solc_cmd.py +10 -0
- mm_eth-0.1.2/tests/cli/test_calcs.py +33 -0
- mm_eth-0.1.2/tests/conftest.py +110 -0
- mm_eth-0.1.2/tests/contracts/ERC20.sol +207 -0
- mm_eth-0.1.2/tests/contracts/abi/ERC20.json +72 -0
- mm_eth-0.1.2/uv.lock +1550 -0
- mm_eth-0.1.1/PKG-INFO +0 -9
- mm_eth-0.1.1/setup.cfg +0 -4
- mm_eth-0.1.1/src/mm_eth.egg-info/PKG-INFO +0 -9
- mm_eth-0.1.1/src/mm_eth.egg-info/SOURCES.txt +0 -60
- mm_eth-0.1.1/src/mm_eth.egg-info/dependency_links.txt +0 -1
- mm_eth-0.1.1/src/mm_eth.egg-info/entry_points.txt +0 -2
- mm_eth-0.1.1/src/mm_eth.egg-info/requires.txt +0 -5
- mm_eth-0.1.1/src/mm_eth.egg-info/top_level.txt +0 -1
- {mm_eth-0.1.1 → mm_eth-0.1.2}/README.txt +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/__init__.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/abi/zksync.json +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/anvil.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/__init__.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/calcs.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cli_helpers.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cli_utils.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/__init__.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/balance_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/balances_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/call_contract_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/config_example_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/deploy_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/encode_input_data_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/mnemonic_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/node_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/private_key_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/rpc_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/send_contract_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/solc_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/token_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/transfer_erc20_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/transfer_eth_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/cmd/vault_cmd.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/config_examples/balances.yml +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/config_examples/call_contract.yml +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/config_examples/transfer_erc20.yml +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/config_examples/transfer_eth.yml +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/cli/validators.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/deploy.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/ens.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/erc20.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/ethernodes.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/py.typed +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/rpc.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/services/__init__.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/solc.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/types.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/src/mm_eth/vault.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_abi.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_account.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_ethernodes.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_rpc.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_tx.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_utils.py +0 -0
- {mm_eth-0.1.1 → mm_eth-0.1.2}/tests/test_zksync.py +0 -0
mm_eth-0.1.2/.gitignore
ADDED
mm_eth-0.1.2/PKG-INFO
ADDED
mm_eth-0.1.2/justfile
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
set dotenv-load
|
|
2
|
+
|
|
3
|
+
version := `uv run python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])'`
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
clean:
|
|
7
|
+
rm -rf .pytest_cache .mypy_cache .ruff_cache .coverage dist build *.egg-info
|
|
8
|
+
|
|
9
|
+
build: clean lint audit test
|
|
10
|
+
uvx --from build pyproject-build --installer uv
|
|
11
|
+
|
|
12
|
+
format:
|
|
13
|
+
uv run ruff check --select I --fix src tests
|
|
14
|
+
uv run ruff format src tests
|
|
15
|
+
|
|
16
|
+
test:
|
|
17
|
+
uv run coverage run -m pytest -n auto tests
|
|
18
|
+
|
|
19
|
+
lint: format
|
|
20
|
+
uv run ruff check src tests
|
|
21
|
+
uv run mypy src
|
|
22
|
+
|
|
23
|
+
audit:
|
|
24
|
+
uv run pip-audit
|
|
25
|
+
uv run bandit -r -c "pyproject.toml" src
|
|
26
|
+
|
|
27
|
+
publish: build
|
|
28
|
+
git diff-index --quiet HEAD
|
|
29
|
+
uvx twine upload dist/**
|
|
30
|
+
git tag -a 'v{{version}}' -m 'v{{version}}'
|
|
31
|
+
git push origin v{{version}}
|
|
32
|
+
|
|
33
|
+
sync:
|
|
34
|
+
uv sync
|
|
35
|
+
|
|
36
|
+
anvil:
|
|
37
|
+
anvil -m "$MNEMONIC"
|
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mm-eth"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = ""
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"mm-std~=0.1.
|
|
7
|
+
"mm-std~=0.1.2",
|
|
8
8
|
"websocket-client~=1.8.0",
|
|
9
|
-
"web3~=
|
|
10
|
-
"typer~=0.12.
|
|
9
|
+
"web3~=7.2.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.
|
|
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.
|
|
26
|
+
"ruff~=0.6.4",
|
|
23
27
|
"pip-audit~=2.7.0",
|
|
24
28
|
"bandit~=1.7.7",
|
|
25
|
-
"mypy~=1.11.
|
|
26
|
-
"types-python-dateutil~=2.9.0.
|
|
27
|
-
"types-requests~=2.32.0.20240523",
|
|
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
|
|
|
@@ -68,3 +71,6 @@ lint.ignore = [
|
|
|
68
71
|
[tool.bandit]
|
|
69
72
|
exclude_dirs = ["tests"]
|
|
70
73
|
skips = ["B311"]
|
|
74
|
+
|
|
75
|
+
[tool.pytest.ini_options]
|
|
76
|
+
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]).
|
|
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()
|
|
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")
|
|
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
|
-
|
|
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
|
|
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.
|
|
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:
|
|
@@ -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
|
|
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,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"
|