mm-balance 0.1.12__tar.gz → 0.1.13__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_balance-0.1.12 → mm_balance-0.1.13}/PKG-INFO +2 -2
- {mm_balance-0.1.12 → mm_balance-0.1.13}/pyproject.toml +2 -2
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/balances.py +8 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/cli.py +1 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/config/example.yml +1 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/config.py +24 -34
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/constants.py +15 -5
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/output.py +13 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/uv.lock +5 -5
- {mm_balance-0.1.12 → mm_balance-0.1.13}/.gitignore +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/README.md +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/justfile +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/__init__.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/price.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/rpc/__init__.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/rpc/btc.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/rpc/eth.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/rpc/solana.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/token_decimals.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/src/mm_balance/total.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/tests/__init__.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/tests/conftest.py +0 -0
- {mm_balance-0.1.12 → mm_balance-0.1.13}/tests/test_dummy.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: mm-balance
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.13
|
|
4
4
|
Requires-Python: >=3.12
|
|
5
5
|
Requires-Dist: mm-btc==0.1.0
|
|
6
6
|
Requires-Dist: mm-eth==0.1.3
|
|
7
|
-
Requires-Dist: mm-solana==0.1.
|
|
7
|
+
Requires-Dist: mm-solana==0.1.5
|
|
8
8
|
Requires-Dist: typer>=0.12.5
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mm-balance"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.13"
|
|
4
4
|
description = ""
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
dependencies = [
|
|
7
7
|
"mm-btc==0.1.0",
|
|
8
8
|
"mm-eth==0.1.3",
|
|
9
|
-
"mm-solana==0.1.
|
|
9
|
+
"mm-solana==0.1.5",
|
|
10
10
|
"typer>=0.12.5",
|
|
11
11
|
]
|
|
12
12
|
[project.scripts]
|
|
@@ -80,3 +80,11 @@ class Balances:
|
|
|
80
80
|
def get_group_balances(self, group_index: int, network: Network) -> list[Balance]:
|
|
81
81
|
# TODO: can we get network by group_index?
|
|
82
82
|
return [b for b in self.tasks[network] if b.group_index == group_index]
|
|
83
|
+
|
|
84
|
+
def get_errors(self) -> list[Balance]:
|
|
85
|
+
result = []
|
|
86
|
+
for network in self.tasks:
|
|
87
|
+
for task in self.tasks[network]:
|
|
88
|
+
if task.balance is not None and task.balance.is_err():
|
|
89
|
+
result.append(task)
|
|
90
|
+
return result
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from decimal import Decimal
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from typing import Self
|
|
5
6
|
|
|
6
7
|
import pydash
|
|
7
8
|
from mm_std import BaseConfig, PrintFormat, fatal, hr
|
|
8
9
|
from pydantic import Field, field_validator, model_validator
|
|
9
10
|
|
|
10
|
-
from mm_balance.constants import
|
|
11
|
-
DEFAULT_ARBITRUM_ONE_NODES,
|
|
12
|
-
DEFAULT_ETHEREUM_NODES,
|
|
13
|
-
DEFAULT_SOLANA_NODES,
|
|
14
|
-
TOKEN_ADDRESS,
|
|
15
|
-
Network,
|
|
16
|
-
)
|
|
11
|
+
from mm_balance.constants import DEFAULT_NODES, TOKEN_ADDRESS, Network
|
|
17
12
|
|
|
18
13
|
|
|
19
14
|
class Group(BaseConfig):
|
|
@@ -34,7 +29,7 @@ class Group(BaseConfig):
|
|
|
34
29
|
return result
|
|
35
30
|
|
|
36
31
|
@field_validator("ticker", mode="after")
|
|
37
|
-
def
|
|
32
|
+
def ticker_validator(cls, v: str) -> str:
|
|
38
33
|
return v.upper()
|
|
39
34
|
|
|
40
35
|
@field_validator("addresses", mode="before")
|
|
@@ -63,7 +58,7 @@ class Group(BaseConfig):
|
|
|
63
58
|
else:
|
|
64
59
|
# TODO: check address is valid
|
|
65
60
|
addresses.append(address)
|
|
66
|
-
self.addresses = addresses
|
|
61
|
+
self.addresses = pydash.uniq(process_file_addresses(addresses))
|
|
67
62
|
|
|
68
63
|
|
|
69
64
|
class AddressGroup(BaseConfig):
|
|
@@ -85,6 +80,7 @@ class Config(BaseConfig):
|
|
|
85
80
|
nodes: dict[Network, list[str]] = Field(default_factory=dict)
|
|
86
81
|
print_format: PrintFormat = PrintFormat.TABLE
|
|
87
82
|
price: bool = True
|
|
83
|
+
skip_empty: bool = False # don't print the address with an empty balance
|
|
88
84
|
|
|
89
85
|
workers: dict[Network, int] = {network: 5 for network in Network}
|
|
90
86
|
|
|
@@ -102,36 +98,16 @@ class Config(BaseConfig):
|
|
|
102
98
|
group.process_addresses(self.addresses)
|
|
103
99
|
|
|
104
100
|
# load default rpc nodes
|
|
105
|
-
|
|
106
|
-
self.nodes
|
|
107
|
-
|
|
108
|
-
self.nodes[Network.ETHEREUM] = DEFAULT_ETHEREUM_NODES
|
|
109
|
-
if Network.ARBITRUM_ONE not in self.nodes:
|
|
110
|
-
self.nodes[Network.ARBITRUM_ONE] = DEFAULT_ARBITRUM_ONE_NODES
|
|
111
|
-
if Network.OP_MAINNET not in self.nodes:
|
|
112
|
-
self.nodes[Network.OP_MAINNET] = DEFAULT_ARBITRUM_ONE_NODES
|
|
113
|
-
if Network.SOLANA not in self.nodes:
|
|
114
|
-
self.nodes[Network.SOLANA] = DEFAULT_SOLANA_NODES
|
|
101
|
+
for network in Network:
|
|
102
|
+
if network not in self.nodes:
|
|
103
|
+
self.nodes[network] = DEFAULT_NODES[network]
|
|
115
104
|
|
|
116
105
|
return self
|
|
117
106
|
|
|
118
107
|
|
|
119
|
-
|
|
120
|
-
#
|
|
121
|
-
# # coin = coin.lower()
|
|
122
|
-
# # if coin == "btc":
|
|
123
|
-
# # return Network.BTC
|
|
124
|
-
# # if coin == "eth":
|
|
125
|
-
# # return Network.ETH
|
|
126
|
-
# # if coin == "sol":
|
|
127
|
-
# # return Network.SOL
|
|
128
|
-
# # return Network.ETH
|
|
129
|
-
# # # TODO: raise ValueError(f"can't get network for the coin: {coin}")
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def detect_token_address(coin: str, network: Network) -> str | None:
|
|
108
|
+
def detect_token_address(ticker: str, network: Network) -> str | None:
|
|
133
109
|
if network in TOKEN_ADDRESS:
|
|
134
|
-
return TOKEN_ADDRESS[network].get(
|
|
110
|
+
return TOKEN_ADDRESS[network].get(ticker)
|
|
135
111
|
|
|
136
112
|
|
|
137
113
|
def get_proxies(proxies_url: str) -> list[str]:
|
|
@@ -147,3 +123,17 @@ def get_proxies(proxies_url: str) -> list[str]:
|
|
|
147
123
|
|
|
148
124
|
def get_address_group_by_name(address_groups: list[AddressGroup], name: str) -> AddressGroup | None:
|
|
149
125
|
return pydash.find(address_groups, lambda g: g.name == name)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def process_file_addresses(addresses: list[str]) -> list[str]:
|
|
129
|
+
result = []
|
|
130
|
+
for address in addresses:
|
|
131
|
+
if address.startswith("file://"):
|
|
132
|
+
path = Path(address.removeprefix("file://"))
|
|
133
|
+
if path.is_file():
|
|
134
|
+
result.extend(path.read_text().strip().splitlines())
|
|
135
|
+
else:
|
|
136
|
+
fatal(f"File with addresses not found: {path}")
|
|
137
|
+
else:
|
|
138
|
+
result.append(address)
|
|
139
|
+
return result
|
|
@@ -27,7 +27,14 @@ TOKEN_ADDRESS: dict[Network, dict[str, str]] = {
|
|
|
27
27
|
"USDT": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
28
28
|
"USDC": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
29
29
|
},
|
|
30
|
-
|
|
30
|
+
Network.ARBITRUM_ONE: {
|
|
31
|
+
"USDT": "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9",
|
|
32
|
+
"USDC": "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8",
|
|
33
|
+
},
|
|
34
|
+
Network.OP_MAINNET: {
|
|
35
|
+
"USDT": "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58",
|
|
36
|
+
"USDC": "0x7f5c764cbc14f9669b88837ca1490cca17c31607",
|
|
37
|
+
},
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
TICKER_TO_COINGECKO_ID = {
|
|
@@ -40,7 +47,10 @@ TICKER_TO_COINGECKO_ID = {
|
|
|
40
47
|
|
|
41
48
|
USD_STABLECOINS = ["USDT", "USDC"]
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
DEFAULT_NODES: dict[Network, list[str]] = {
|
|
51
|
+
Network.ARBITRUM_ONE: ["https://arb1.arbitrum.io/rpc", "https://arbitrum.llamarpc.com"],
|
|
52
|
+
Network.BITCOIN: [],
|
|
53
|
+
Network.ETHEREUM: ["https://ethereum.publicnode.com", "https://rpc.ankr.com/eth"],
|
|
54
|
+
Network.SOLANA: ["https://api.mainnet-beta.solana.com"],
|
|
55
|
+
Network.OP_MAINNET: ["https://mainnet.optimism.io", "https://optimism.llamarpc.com"],
|
|
56
|
+
}
|
|
@@ -20,6 +20,8 @@ def _print_group(group: Group, group_balances: list[Balances.Balance], config: C
|
|
|
20
20
|
balance_sum = Decimal(0)
|
|
21
21
|
usd_sum = Decimal(0)
|
|
22
22
|
for address_task in group_balances:
|
|
23
|
+
if config.skip_empty and isinstance(address_task.balance, Ok) and address_task.balance.ok == Decimal(0):
|
|
24
|
+
continue
|
|
23
25
|
row = [address_task.address, address_task.balance.ok_or_err()] # type: ignore[union-attr]
|
|
24
26
|
if isinstance(address_task.balance, Ok):
|
|
25
27
|
balance_sum += address_task.balance.ok
|
|
@@ -57,6 +59,17 @@ def print_total(config: Config, balances: Balances, prices: Prices) -> None:
|
|
|
57
59
|
total.print()
|
|
58
60
|
|
|
59
61
|
|
|
62
|
+
def print_errors(config: Config, balances: Balances) -> None:
|
|
63
|
+
error_balances = balances.get_errors()
|
|
64
|
+
if not error_balances:
|
|
65
|
+
return
|
|
66
|
+
rows = []
|
|
67
|
+
for balance in error_balances:
|
|
68
|
+
group = config.groups[balance.group_index]
|
|
69
|
+
rows.append([group.ticker + " / " + group.network, balance.address, balance.balance.err]) # type: ignore[union-attr]
|
|
70
|
+
print_table("Errors", ["coin", "address", "error"], rows)
|
|
71
|
+
|
|
72
|
+
|
|
60
73
|
def create_progress_bar() -> Progress:
|
|
61
74
|
return Progress(
|
|
62
75
|
TextColumn("[progress.description]{task.description}"),
|
|
@@ -925,7 +925,7 @@ wheels = [
|
|
|
925
925
|
|
|
926
926
|
[[package]]
|
|
927
927
|
name = "mm-balance"
|
|
928
|
-
version = "0.1.
|
|
928
|
+
version = "0.1.13"
|
|
929
929
|
source = { editable = "." }
|
|
930
930
|
dependencies = [
|
|
931
931
|
{ name = "mm-btc" },
|
|
@@ -952,7 +952,7 @@ dev = [
|
|
|
952
952
|
requires-dist = [
|
|
953
953
|
{ name = "mm-btc", specifier = "==0.1.0" },
|
|
954
954
|
{ name = "mm-eth", specifier = "==0.1.3" },
|
|
955
|
-
{ name = "mm-solana", specifier = "==0.1.
|
|
955
|
+
{ name = "mm-solana", specifier = "==0.1.5" },
|
|
956
956
|
{ name = "typer", specifier = ">=0.12.5" },
|
|
957
957
|
]
|
|
958
958
|
|
|
@@ -1004,7 +1004,7 @@ wheels = [
|
|
|
1004
1004
|
|
|
1005
1005
|
[[package]]
|
|
1006
1006
|
name = "mm-solana"
|
|
1007
|
-
version = "0.1.
|
|
1007
|
+
version = "0.1.5"
|
|
1008
1008
|
source = { registry = "https://pypi.org/simple" }
|
|
1009
1009
|
dependencies = [
|
|
1010
1010
|
{ name = "base58" },
|
|
@@ -1015,9 +1015,9 @@ dependencies = [
|
|
|
1015
1015
|
{ name = "solana" },
|
|
1016
1016
|
{ name = "typer" },
|
|
1017
1017
|
]
|
|
1018
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1018
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d9/ad/2cd6a536f8d314e2fc37d85d00b1a3a67e1731fded3b4fa82a9ca18c4eec/mm_solana-0.1.5.tar.gz", hash = "sha256:00be9fe5486484b6f31240b76ea7c7a33d364f818252bd3bb314b9b6926aed8c", size = 51391 }
|
|
1019
1019
|
wheels = [
|
|
1020
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1020
|
+
{ url = "https://files.pythonhosted.org/packages/29/53/75850218681cfe1a5b3bff02703193cfa89d7c41d776718df6a2c183774f/mm_solana-0.1.5-py3-none-any.whl", hash = "sha256:4d441791b8c14134651d9b27a3bee617b565b6390ad47a012efe4ad42eca8b92", size = 18927 },
|
|
1021
1021
|
]
|
|
1022
1022
|
|
|
1023
1023
|
[[package]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|