mm-balance 0.1.19__py3-none-any.whl → 0.2.0__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_balance/cli.py +15 -12
- mm_balance/config/example.toml +83 -0
- mm_balance/config.py +21 -50
- mm_balance/output/formats/json_format.py +3 -3
- mm_balance/output/formats/table_format.py +22 -20
- mm_balance/price.py +1 -1
- mm_balance/result.py +1 -1
- mm_balance/rpc/btc.py +1 -3
- mm_balance/rpc/solana.py +6 -5
- mm_balance/token_decimals.py +1 -1
- mm_balance/workers.py +4 -7
- mm_balance-0.2.0.dist-info/METADATA +9 -0
- mm_balance-0.2.0.dist-info/RECORD +24 -0
- mm_balance/config/example.yml +0 -74
- mm_balance-0.1.19.dist-info/METADATA +0 -9
- mm_balance-0.1.19.dist-info/RECORD +0 -24
- {mm_balance-0.1.19.dist-info → mm_balance-0.2.0.dist-info}/WHEEL +0 -0
- {mm_balance-0.1.19.dist-info → mm_balance-0.2.0.dist-info}/entry_points.txt +0 -0
mm_balance/cli.py
CHANGED
|
@@ -19,7 +19,7 @@ app = typer.Typer(no_args_is_help=True, pretty_exceptions_enable=False, add_comp
|
|
|
19
19
|
|
|
20
20
|
def example_callback(value: bool) -> None:
|
|
21
21
|
if value:
|
|
22
|
-
data = pkgutil.get_data(__name__, "config/example.
|
|
22
|
+
data = pkgutil.get_data(__name__, "config/example.toml")
|
|
23
23
|
typer.echo(data)
|
|
24
24
|
raise typer.Exit
|
|
25
25
|
|
|
@@ -37,6 +37,7 @@ def cli(
|
|
|
37
37
|
print_format: Annotated[PrintFormat | None, typer.Option("--format", "-f", help="Print format.")] = None,
|
|
38
38
|
skip_empty: Annotated[bool | None, typer.Option("--skip-empty", "-s", help="Skip empty balances.")] = None,
|
|
39
39
|
debug: Annotated[bool | None, typer.Option("--debug", "-d", help="Print debug info.")] = None,
|
|
40
|
+
print_config: Annotated[bool | None, typer.Option("--config", "-c", help="Print config and exit.")] = None,
|
|
40
41
|
price: Annotated[bool | None, typer.Option("--price/--no-price", help="Print prices.")] = None,
|
|
41
42
|
_example: Annotated[bool | None, typer.Option("--example", callback=example_callback, help="Print a config example.")] = None,
|
|
42
43
|
_networks: Annotated[
|
|
@@ -46,36 +47,38 @@ def cli(
|
|
|
46
47
|
zip_password = "" # nosec
|
|
47
48
|
if config_path.name.endswith(".zip"):
|
|
48
49
|
zip_password = getpass.getpass("zip password")
|
|
49
|
-
config = Config.
|
|
50
|
+
config = Config.read_toml_config_or_exit(config_path, zip_password=zip_password)
|
|
51
|
+
if print_config:
|
|
52
|
+
config.print_and_exit()
|
|
50
53
|
|
|
51
54
|
if print_format is not None:
|
|
52
|
-
config.print_format = print_format
|
|
55
|
+
config.settings.print_format = print_format
|
|
53
56
|
if debug is not None:
|
|
54
|
-
config.print_debug = debug
|
|
57
|
+
config.settings.print_debug = debug
|
|
55
58
|
if skip_empty is not None:
|
|
56
|
-
config.skip_empty = skip_empty
|
|
59
|
+
config.settings.skip_empty = skip_empty
|
|
57
60
|
if price is not None:
|
|
58
|
-
config.price = price
|
|
61
|
+
config.settings.price = price
|
|
59
62
|
|
|
60
|
-
if config.print_debug and config.print_format is PrintFormat.TABLE:
|
|
63
|
+
if config.settings.print_debug and config.settings.print_format is PrintFormat.TABLE:
|
|
61
64
|
table_format.print_nodes(config)
|
|
62
65
|
table_format.print_proxy_count(config)
|
|
63
66
|
|
|
64
67
|
token_decimals = get_token_decimals(config)
|
|
65
|
-
if config.print_debug and config.print_format is PrintFormat.TABLE:
|
|
68
|
+
if config.settings.print_debug and config.settings.print_format is PrintFormat.TABLE:
|
|
66
69
|
table_format.print_token_decimals(token_decimals)
|
|
67
70
|
|
|
68
|
-
prices = get_prices(config) if config.price else Prices()
|
|
69
|
-
if config.print_format is PrintFormat.TABLE:
|
|
71
|
+
prices = get_prices(config) if config.settings.price else Prices()
|
|
72
|
+
if config.settings.print_format is PrintFormat.TABLE:
|
|
70
73
|
table_format.print_prices(config, prices)
|
|
71
74
|
|
|
72
75
|
workers = Workers(config, token_decimals)
|
|
73
76
|
workers.process()
|
|
74
77
|
|
|
75
78
|
result = create_balances_result(config, prices, workers)
|
|
76
|
-
if config.print_format is PrintFormat.TABLE:
|
|
79
|
+
if config.settings.print_format is PrintFormat.TABLE:
|
|
77
80
|
table_format.print_result(config, result, workers)
|
|
78
|
-
elif config.print_format is PrintFormat.JSON:
|
|
81
|
+
elif config.settings.print_format is PrintFormat.JSON:
|
|
79
82
|
json_format.print_result(config, token_decimals, prices, workers, result)
|
|
80
83
|
else:
|
|
81
84
|
fatal("Unsupported print format")
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
[[coins]]
|
|
2
|
+
ticker = "SOL"
|
|
3
|
+
network = "solana"
|
|
4
|
+
addresses = "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" # binance
|
|
5
|
+
|
|
6
|
+
[[coins]]
|
|
7
|
+
ticker = "USDT"
|
|
8
|
+
network = "solana"
|
|
9
|
+
addresses = "2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S" # binance
|
|
10
|
+
|
|
11
|
+
[[coins]]
|
|
12
|
+
ticker = "BTC"
|
|
13
|
+
network = "bitcoin"
|
|
14
|
+
comment = "coldwallets"
|
|
15
|
+
addresses = """
|
|
16
|
+
34xp4vRoCGJym3xR7yCVPFHoCNxv4Twseo # binance
|
|
17
|
+
bc1qgdjqv0av3q56jvd82tkdjpy7gdp9ut8tlqmgrpmv24sq90ecnvqqjwvw97 # bitfinex
|
|
18
|
+
bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2 # robinhood
|
|
19
|
+
"""
|
|
20
|
+
share = 0.1
|
|
21
|
+
|
|
22
|
+
[[coins]]
|
|
23
|
+
ticker = "ETH"
|
|
24
|
+
network = "ethereum"
|
|
25
|
+
comment = "okx"
|
|
26
|
+
addresses = "okx_eth"
|
|
27
|
+
|
|
28
|
+
[[coins]]
|
|
29
|
+
ticker = "USDT"
|
|
30
|
+
network = "ethereum"
|
|
31
|
+
comment = "okx"
|
|
32
|
+
addresses = "okx_eth"
|
|
33
|
+
|
|
34
|
+
[[coins]]
|
|
35
|
+
ticker = "ETH"
|
|
36
|
+
network = "ethereum"
|
|
37
|
+
comment = "binance"
|
|
38
|
+
addresses = "binance_eth"
|
|
39
|
+
|
|
40
|
+
[[coins]]
|
|
41
|
+
ticker = "USDT"
|
|
42
|
+
network = "ethereum"
|
|
43
|
+
comment = "binance"
|
|
44
|
+
addresses = "binance_eth"
|
|
45
|
+
|
|
46
|
+
[[coins]]
|
|
47
|
+
ticker = "USDC"
|
|
48
|
+
network = "aptos"
|
|
49
|
+
comment = "swap.thala.apt"
|
|
50
|
+
token_address = "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC"
|
|
51
|
+
token_decimals = 6
|
|
52
|
+
addresses = "0x48271d39d0b05bd6efca2278f22277d6fcc375504f9839fd73f74ace240861af"
|
|
53
|
+
|
|
54
|
+
[[addresses]]
|
|
55
|
+
name = "okx_eth"
|
|
56
|
+
addresses = """
|
|
57
|
+
0xf59869753f41db720127ceb8dbb8afaf89030de4
|
|
58
|
+
0x65a0947ba5175359bb457d3b34491edf4cbf7997
|
|
59
|
+
0xe9172daf64b05b26eb18f07ac8d6d723acb48f99
|
|
60
|
+
0x4d19c0a5357bc48be0017095d3c871d9afc3f21d
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
[[addresses]]
|
|
64
|
+
name = "binance_eth"
|
|
65
|
+
addresses = """
|
|
66
|
+
0xf977814e90da44bfa03b6295a0616a897441acec
|
|
67
|
+
0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
[settings] # all records are optional
|
|
72
|
+
round_ndigits = 4
|
|
73
|
+
price = true
|
|
74
|
+
skip_empty = false
|
|
75
|
+
print_debug = false
|
|
76
|
+
print_format = "table" # table, json
|
|
77
|
+
format_number_separator = ","
|
|
78
|
+
proxies = """
|
|
79
|
+
env_url: MM_BALANCE_PROXIES_URL
|
|
80
|
+
# socks5://usr:pass@site.com:1234
|
|
81
|
+
# http://site.com:1234
|
|
82
|
+
"""
|
|
83
|
+
|
mm_balance/config.py
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import os
|
|
4
3
|
from decimal import Decimal
|
|
5
4
|
from pathlib import Path
|
|
6
|
-
from typing import
|
|
5
|
+
from typing import Annotated, Self
|
|
7
6
|
|
|
8
7
|
import pydash
|
|
9
|
-
from
|
|
10
|
-
from
|
|
8
|
+
from mm_crypto_utils import ConfigValidators
|
|
9
|
+
from mm_std import BaseConfig, PrintFormat, fatal
|
|
10
|
+
from pydantic import BeforeValidator, Field, StringConstraints, model_validator
|
|
11
11
|
|
|
12
12
|
from mm_balance.constants import DEFAULT_NODES, TOKEN_ADDRESS, Network
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
class Validators(ConfigValidators):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
15
19
|
class Group(BaseConfig):
|
|
16
20
|
comment: str = ""
|
|
17
|
-
ticker: str
|
|
21
|
+
ticker: Annotated[str, StringConstraints(to_upper=True)]
|
|
18
22
|
network: Network
|
|
19
23
|
token_address: str | None = None # If None, it's a native token, for example ETH
|
|
20
24
|
token_decimals: int | None = None
|
|
21
25
|
coingecko_id: str | None = None
|
|
22
|
-
addresses: list[str]
|
|
26
|
+
addresses: Annotated[list[str], BeforeValidator(Validators.addresses(unique=True))]
|
|
23
27
|
share: Decimal = Decimal(1)
|
|
24
28
|
|
|
25
29
|
@property
|
|
@@ -30,20 +34,6 @@ class Group(BaseConfig):
|
|
|
30
34
|
result += " / " + self.network
|
|
31
35
|
return result
|
|
32
36
|
|
|
33
|
-
@field_validator("ticker", mode="after")
|
|
34
|
-
def ticker_validator(cls, v: str) -> str:
|
|
35
|
-
return v.upper()
|
|
36
|
-
|
|
37
|
-
@field_validator("addresses", mode="before")
|
|
38
|
-
def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
|
|
39
|
-
return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
|
|
40
|
-
|
|
41
|
-
# @model_validator(mode="before")
|
|
42
|
-
# def before_all(cls, data: Any) -> Any:
|
|
43
|
-
# if "network" not in data:
|
|
44
|
-
# data["network"] = detect_network(data["coin"])
|
|
45
|
-
# return data
|
|
46
|
-
|
|
47
37
|
@model_validator(mode="after")
|
|
48
38
|
def final_validator(self) -> Self:
|
|
49
39
|
if self.token_address is None:
|
|
@@ -65,27 +55,25 @@ class Group(BaseConfig):
|
|
|
65
55
|
|
|
66
56
|
class AddressGroup(BaseConfig):
|
|
67
57
|
name: str
|
|
68
|
-
addresses: list[str]
|
|
58
|
+
addresses: Annotated[list[str], BeforeValidator(ConfigValidators.addresses(unique=True))]
|
|
69
59
|
|
|
70
|
-
@field_validator("addresses", mode="before")
|
|
71
|
-
def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
|
|
72
|
-
return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class Config(BaseConfig):
|
|
76
|
-
groups: list[Group] = Field(alias="coins")
|
|
77
|
-
addresses: list[AddressGroup] = Field(default_factory=list)
|
|
78
60
|
|
|
79
|
-
|
|
80
|
-
proxies: list[str]
|
|
61
|
+
class Settings(BaseConfig):
|
|
62
|
+
proxies: Annotated[list[str], Field(default_factory=list), BeforeValidator(Validators.proxies())]
|
|
81
63
|
round_ndigits: int = 4
|
|
82
|
-
nodes: dict[Network, list[str]] = Field(default_factory=dict)
|
|
83
64
|
print_format: PrintFormat = PrintFormat.TABLE
|
|
84
65
|
price: bool = True
|
|
85
66
|
skip_empty: bool = False # don't print the address with an empty balance
|
|
86
67
|
print_debug: bool = False # print debug info: nodes, token_decimals
|
|
87
|
-
format_number_separator: str = "," #
|
|
68
|
+
format_number_separator: str = "," # as thousands separators
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Config(BaseConfig):
|
|
72
|
+
groups: list[Group] = Field(alias="coins")
|
|
73
|
+
addresses: list[AddressGroup] = Field(default_factory=list)
|
|
74
|
+
nodes: dict[Network, list[str]] = Field(default_factory=dict)
|
|
88
75
|
workers: dict[Network, int] = Field(default_factory=dict)
|
|
76
|
+
settings: Settings = Field(default_factory=Settings) # type: ignore[arg-type]
|
|
89
77
|
|
|
90
78
|
def has_share(self) -> bool:
|
|
91
79
|
return any(g.share != Decimal(1) for g in self.groups)
|
|
@@ -95,12 +83,6 @@ class Config(BaseConfig):
|
|
|
95
83
|
|
|
96
84
|
@model_validator(mode="after")
|
|
97
85
|
def final_validator(self) -> Self:
|
|
98
|
-
# load from proxies_url
|
|
99
|
-
if self.proxies_url is not None:
|
|
100
|
-
self.proxies = get_proxies(self.proxies_url)
|
|
101
|
-
elif os.getenv("MM_BALANCE_PROXIES_URL"):
|
|
102
|
-
self.proxies = get_proxies(cast(str, os.getenv("MM_BALANCE_PROXIES_URL")))
|
|
103
|
-
|
|
104
86
|
# load addresses from address_group
|
|
105
87
|
for group in self.groups:
|
|
106
88
|
group.process_addresses(self.addresses)
|
|
@@ -123,17 +105,6 @@ def detect_token_address(ticker: str, network: Network) -> str | None:
|
|
|
123
105
|
return TOKEN_ADDRESS[network].get(ticker)
|
|
124
106
|
|
|
125
107
|
|
|
126
|
-
def get_proxies(proxies_url: str) -> list[str]:
|
|
127
|
-
try:
|
|
128
|
-
res = hr(proxies_url)
|
|
129
|
-
if res.is_error():
|
|
130
|
-
fatal(f"Can't get proxies: {res.error}")
|
|
131
|
-
proxies = [p.strip() for p in res.body.splitlines() if p.strip()]
|
|
132
|
-
return pydash.uniq(proxies)
|
|
133
|
-
except Exception as err:
|
|
134
|
-
fatal(f"Can't get proxies: {err}")
|
|
135
|
-
|
|
136
|
-
|
|
137
108
|
def get_address_group_by_name(address_groups: list[AddressGroup], name: str) -> AddressGroup | None:
|
|
138
109
|
return pydash.find(address_groups, lambda g: g.name == name)
|
|
139
110
|
|
|
@@ -9,11 +9,11 @@ from mm_balance.workers import Workers
|
|
|
9
9
|
|
|
10
10
|
def print_result(config: Config, token_decimals: TokenDecimals, prices: Prices, workers: Workers, result: BalancesResult) -> None:
|
|
11
11
|
data: dict[str, object] = {}
|
|
12
|
-
if config.print_debug:
|
|
12
|
+
if config.settings.print_debug:
|
|
13
13
|
data["nodes"] = config.nodes
|
|
14
14
|
data["token_decimals"] = token_decimals
|
|
15
|
-
data["proxies"] = len(config.proxies)
|
|
16
|
-
if config.price:
|
|
15
|
+
data["proxies"] = len(config.settings.proxies)
|
|
16
|
+
if config.settings.price:
|
|
17
17
|
data["prices"] = prices
|
|
18
18
|
|
|
19
19
|
data["groups"] = result.groups
|
|
@@ -18,7 +18,7 @@ def print_nodes(config: Config) -> None:
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def print_proxy_count(config: Config) -> None:
|
|
21
|
-
print_table("Proxies", ["count"], [[len(config.proxies)]])
|
|
21
|
+
print_table("Proxies", ["count"], [[len(config.settings.proxies)]])
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def print_token_decimals(token_decimals: TokenDecimals) -> None:
|
|
@@ -29,10 +29,12 @@ def print_token_decimals(token_decimals: TokenDecimals) -> None:
|
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def print_prices(config: Config, prices: Prices) -> None:
|
|
32
|
-
if config.price:
|
|
32
|
+
if config.settings.price:
|
|
33
33
|
rows = []
|
|
34
34
|
for ticker, price in prices.items():
|
|
35
|
-
rows.append(
|
|
35
|
+
rows.append(
|
|
36
|
+
[ticker, format_number(round(price, config.settings.round_ndigits), config.settings.format_number_separator, "$")]
|
|
37
|
+
)
|
|
36
38
|
print_table("Prices", ["coin", "usd"], rows)
|
|
37
39
|
|
|
38
40
|
|
|
@@ -64,19 +66,19 @@ def _print_total(config: Config, total: Total, is_share_total: bool) -> None:
|
|
|
64
66
|
|
|
65
67
|
rows = []
|
|
66
68
|
for ticker, balance in total.coin_balances.items():
|
|
67
|
-
balance_str = format_number(balance, config.format_number_separator)
|
|
69
|
+
balance_str = format_number(balance, config.settings.format_number_separator)
|
|
68
70
|
row = [ticker, balance_str]
|
|
69
|
-
if config.price:
|
|
70
|
-
usd_value_str = format_number(total.coin_usd_values[ticker], config.format_number_separator, "$")
|
|
71
|
+
if config.settings.price:
|
|
72
|
+
usd_value_str = format_number(total.coin_usd_values[ticker], config.settings.format_number_separator, "$")
|
|
71
73
|
portfolio_share = total.portfolio_share[ticker]
|
|
72
74
|
row += [usd_value_str, f"{portfolio_share}%"]
|
|
73
75
|
rows.append(row)
|
|
74
76
|
|
|
75
|
-
if config.price:
|
|
77
|
+
if config.settings.price:
|
|
76
78
|
headers += ["usd", "portfolio_share"]
|
|
77
79
|
if total.stablecoin_sum > 0:
|
|
78
|
-
rows.append(["stablecoin_sum", format_number(total.stablecoin_sum, config.format_number_separator, "$")])
|
|
79
|
-
rows.append(["total_usd_sum", format_number(total.total_usd_sum, config.format_number_separator, "$")])
|
|
80
|
+
rows.append(["stablecoin_sum", format_number(total.stablecoin_sum, config.settings.format_number_separator, "$")])
|
|
81
|
+
rows.append(["total_usd_sum", format_number(total.total_usd_sum, config.settings.format_number_separator, "$")])
|
|
80
82
|
|
|
81
83
|
print_table(table_name, headers, rows)
|
|
82
84
|
|
|
@@ -92,28 +94,28 @@ def _print_group(config: Config, group: GroupResult) -> None:
|
|
|
92
94
|
if isinstance(address.balance, str):
|
|
93
95
|
rows.append([address.address, address.balance])
|
|
94
96
|
else:
|
|
95
|
-
if config.skip_empty and address.balance.balance == Decimal(0):
|
|
97
|
+
if config.settings.skip_empty and address.balance.balance == Decimal(0):
|
|
96
98
|
continue
|
|
97
|
-
balance_str = format_number(address.balance.balance, config.format_number_separator)
|
|
99
|
+
balance_str = format_number(address.balance.balance, config.settings.format_number_separator)
|
|
98
100
|
row = [address.address, balance_str]
|
|
99
|
-
if config.price:
|
|
100
|
-
usd_value_str = format_number(address.balance.usd_value, config.format_number_separator, "$")
|
|
101
|
+
if config.settings.price:
|
|
102
|
+
usd_value_str = format_number(address.balance.usd_value, config.settings.format_number_separator, "$")
|
|
101
103
|
row.append(usd_value_str)
|
|
102
104
|
rows.append(row)
|
|
103
105
|
|
|
104
|
-
sum_row = ["sum", format_number(group.balance_sum, config.format_number_separator)]
|
|
105
|
-
if config.price:
|
|
106
|
-
sum_row.append(format_number(group.usd_sum, config.format_number_separator, "$"))
|
|
106
|
+
sum_row = ["sum", format_number(group.balance_sum, config.settings.format_number_separator)]
|
|
107
|
+
if config.settings.price:
|
|
108
|
+
sum_row.append(format_number(group.usd_sum, config.settings.format_number_separator, "$"))
|
|
107
109
|
rows.append(sum_row)
|
|
108
110
|
|
|
109
111
|
if group.share < Decimal(1):
|
|
110
|
-
sum_share_str = format_number(group.balance_sum_share, config.format_number_separator)
|
|
112
|
+
sum_share_str = format_number(group.balance_sum_share, config.settings.format_number_separator)
|
|
111
113
|
sum_share_row = [f"sum_share, {group.share}", sum_share_str]
|
|
112
|
-
if config.price:
|
|
113
|
-
sum_share_row.append(format_number(group.usd_sum_share, config.format_number_separator, "$"))
|
|
114
|
+
if config.settings.price:
|
|
115
|
+
sum_share_row.append(format_number(group.usd_sum_share, config.settings.format_number_separator, "$"))
|
|
114
116
|
rows.append(sum_share_row)
|
|
115
117
|
|
|
116
118
|
table_headers = ["address", "balance"]
|
|
117
|
-
if config.price:
|
|
119
|
+
if config.settings.price:
|
|
118
120
|
table_headers += ["usd"]
|
|
119
121
|
print_table(group_name, table_headers, rows)
|
mm_balance/price.py
CHANGED
|
@@ -30,7 +30,7 @@ def get_prices(config: Config) -> Prices:
|
|
|
30
30
|
|
|
31
31
|
url = f"https://api.coingecko.com/api/v3/simple/price?ids={','.join(coingecko_map.values())}&vs_currencies=usd"
|
|
32
32
|
for _ in range(RETRIES_COINGECKO_PRICES):
|
|
33
|
-
res = hr(url, proxy=random_str_choice(config.proxies))
|
|
33
|
+
res = hr(url, proxy=random_str_choice(config.settings.proxies))
|
|
34
34
|
if res.code != 200:
|
|
35
35
|
continue
|
|
36
36
|
|
mm_balance/result.py
CHANGED
|
@@ -106,7 +106,7 @@ def _create_group_result(config: Config, group: Group, tasks: list[Task], prices
|
|
|
106
106
|
coin_value = task.balance.ok
|
|
107
107
|
usd_value = Decimal(0)
|
|
108
108
|
if group.ticker in prices:
|
|
109
|
-
usd_value = round(coin_value * prices[group.ticker], config.round_ndigits)
|
|
109
|
+
usd_value = round(coin_value * prices[group.ticker], config.settings.round_ndigits)
|
|
110
110
|
balance = Balance(balance=coin_value, usd_value=usd_value)
|
|
111
111
|
balance_sum += balance.balance
|
|
112
112
|
usd_sum += balance.usd_value
|
mm_balance/rpc/btc.py
CHANGED
|
@@ -10,7 +10,5 @@ def get_balance(address: str, proxies: list[str], round_ndigits: int) -> Result[
|
|
|
10
10
|
return (
|
|
11
11
|
BlockstreamClient(proxies=proxies, attempts=RETRIES_BALANCE)
|
|
12
12
|
.get_confirmed_balance(address)
|
|
13
|
-
.and_then(
|
|
14
|
-
lambda b: Ok(round(Decimal(b / 100_000_000), round_ndigits)),
|
|
15
|
-
)
|
|
13
|
+
.and_then(lambda b: Ok(round(Decimal(b / 100_000_000), round_ndigits)))
|
|
16
14
|
)
|
mm_balance/rpc/solana.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from decimal import Decimal
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from mm_solana import token as solana_token
|
|
3
|
+
from mm_sol import balance, token
|
|
5
4
|
from mm_std import Ok, Result
|
|
6
5
|
|
|
7
6
|
from mm_balance.constants import RETRIES_BALANCE, RETRIES_DECIMALS, TIMEOUT_BALANCE, TIMEOUT_DECIMALS
|
|
@@ -11,9 +10,11 @@ def get_balance(
|
|
|
11
10
|
nodes: list[str], wallet: str, token: str | None, decimals: int, proxies: list[str], round_ndigits: int
|
|
12
11
|
) -> Result[Decimal]:
|
|
13
12
|
if token is None:
|
|
14
|
-
res = balance.
|
|
13
|
+
res = balance.get_sol_balance_with_retries(
|
|
14
|
+
nodes, wallet, retries=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE, proxies=proxies
|
|
15
|
+
)
|
|
15
16
|
else:
|
|
16
|
-
res =
|
|
17
|
+
res = balance.get_token_balance_with_retries(
|
|
17
18
|
nodes, wallet, token, retries=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE, proxies=proxies
|
|
18
19
|
)
|
|
19
20
|
|
|
@@ -21,6 +22,6 @@ def get_balance(
|
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
|
|
24
|
-
return
|
|
25
|
+
return token.get_decimals_with_retries(
|
|
25
26
|
nodes, token_address, retries=RETRIES_DECIMALS, timeout=TIMEOUT_DECIMALS, proxies=proxies
|
|
26
27
|
)
|
mm_balance/token_decimals.py
CHANGED
|
@@ -14,7 +14,7 @@ class TokenDecimals(dict[Network, dict[str | None, int]]): # {network: {None: 1
|
|
|
14
14
|
|
|
15
15
|
def get_token_decimals(config: Config) -> TokenDecimals:
|
|
16
16
|
result = TokenDecimals(config.networks())
|
|
17
|
-
proxies = config.proxies
|
|
17
|
+
proxies = config.settings.proxies
|
|
18
18
|
|
|
19
19
|
for group in config.groups:
|
|
20
20
|
# token_decimals is already known
|
mm_balance/workers.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from decimal import Decimal
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
3
|
|
|
5
4
|
from mm_std import ConcurrentTasks, PrintFormat, Result
|
|
5
|
+
from rich.progress import TaskID
|
|
6
6
|
|
|
7
7
|
from mm_balance.config import Config
|
|
8
8
|
from mm_balance.constants import NETWORK_APTOS, NETWORK_BITCOIN, NETWORK_SOLANA, Network
|
|
@@ -10,9 +10,6 @@ from mm_balance.output import utils
|
|
|
10
10
|
from mm_balance.rpc import aptos, btc, evm, solana
|
|
11
11
|
from mm_balance.token_decimals import TokenDecimals
|
|
12
12
|
|
|
13
|
-
if TYPE_CHECKING:
|
|
14
|
-
from rich.progress import TaskID
|
|
15
|
-
|
|
16
13
|
|
|
17
14
|
@dataclass
|
|
18
15
|
class Task:
|
|
@@ -27,7 +24,7 @@ class Workers:
|
|
|
27
24
|
self.config = config
|
|
28
25
|
self.token_decimals = token_decimals
|
|
29
26
|
self.tasks: dict[Network, list[Task]] = {network: [] for network in config.networks()}
|
|
30
|
-
self.progress_bar = utils.create_progress_bar(config.print_format is not PrintFormat.TABLE)
|
|
27
|
+
self.progress_bar = utils.create_progress_bar(config.settings.print_format is not PrintFormat.TABLE)
|
|
31
28
|
self.progress_bar_task: dict[Network, TaskID] = {}
|
|
32
29
|
|
|
33
30
|
for idx, group in enumerate(config.groups):
|
|
@@ -66,8 +63,8 @@ class Workers:
|
|
|
66
63
|
|
|
67
64
|
def _get_balance(self, network: Network, wallet_address: str, token_address: str | None) -> Result[Decimal]:
|
|
68
65
|
nodes = self.config.nodes[network]
|
|
69
|
-
round_ndigits = self.config.round_ndigits
|
|
70
|
-
proxies = self.config.proxies
|
|
66
|
+
round_ndigits = self.config.settings.round_ndigits
|
|
67
|
+
proxies = self.config.settings.proxies
|
|
71
68
|
token_decimals = self.token_decimals[network][token_address]
|
|
72
69
|
|
|
73
70
|
if network.is_evm_network():
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
mm_balance/cli.py,sha256=glOveB7bhcmuHBZvKZpmO1iMB1S21E6TnIIwuB25jUo,3398
|
|
3
|
+
mm_balance/config.py,sha256=wuNiy8RBoFhisx4ZvT7CAXDvvz4aU52kr4vXFnXNvGI,4381
|
|
4
|
+
mm_balance/constants.py,sha256=kqG2zuwv0l-PzDHIrMJVQpfQWiXjr2DsqGPcKmqNJLo,2334
|
|
5
|
+
mm_balance/price.py,sha256=DzvcQngS6wgi_4YWoXxGvOuOkwJvUbN0KI8DeIxbB5A,1494
|
|
6
|
+
mm_balance/result.py,sha256=WsVLbf54cCJ76rIM2zHaOCQXMfZZMczdg8rlC2tDGWY,4533
|
|
7
|
+
mm_balance/token_decimals.py,sha256=7XL_x_1ZIhp_cr1TvXwnqLqINUWFGo0j5_5lWuxmwpE,2277
|
|
8
|
+
mm_balance/utils.py,sha256=bngYS2WFIakGZO31_ey4MPsllvDhgOxkAnGiXqom3J4,286
|
|
9
|
+
mm_balance/workers.py,sha256=vEmmUI-ioMOv1C_Jcz0rnzI3vn7BaVWFnyXddteJkoA,3766
|
|
10
|
+
mm_balance/config/example.toml,sha256=RuZQfizuPgX0F9MQdVffDfKrCOJxJE48iPbM9HT96wk,1786
|
|
11
|
+
mm_balance/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
mm_balance/output/utils.py,sha256=WUFwshFMKZKdcwRtO21nhxqW78JeLAatDyHPZhdV96A,716
|
|
13
|
+
mm_balance/output/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
mm_balance/output/formats/json_format.py,sha256=japDhWBVaZ9Znwrhi6BLsUEyn2zyNVxPFYhH7SiILb8,893
|
|
15
|
+
mm_balance/output/formats/table_format.py,sha256=o_3MGOb0Ug9sqfaR61JDucSEtmFF22KlJoqpFWRuFu8,4758
|
|
16
|
+
mm_balance/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
mm_balance/rpc/aptos.py,sha256=1JCYCqDim4tk1axXscaAJRXPd4J6vV1ABFbwMbPgrL0,641
|
|
18
|
+
mm_balance/rpc/btc.py,sha256=iGDoO7HXP6reLI0bWm0UhEl7-UFZTo5xCWNzFngbITw,458
|
|
19
|
+
mm_balance/rpc/evm.py,sha256=ewlMmRrcXKlky3DPNbnUBTVwnvyw7N9iCZLsCX2V14w,1007
|
|
20
|
+
mm_balance/rpc/solana.py,sha256=c756415rlhQkHsVsqxHcA7wIaSM64IqyxMohjz8IGhY,1031
|
|
21
|
+
mm_balance-0.2.0.dist-info/METADATA,sha256=eG5IbPKRNnqBK_go58psO14Go5FUAAWWsHE4xBjgyak,225
|
|
22
|
+
mm_balance-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
23
|
+
mm_balance-0.2.0.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
|
|
24
|
+
mm_balance-0.2.0.dist-info/RECORD,,
|
mm_balance/config/example.yml
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
coins:
|
|
2
|
-
- ticker: SOL
|
|
3
|
-
network: solana
|
|
4
|
-
addresses:
|
|
5
|
-
- 2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S # binance
|
|
6
|
-
|
|
7
|
-
- ticker: USDT
|
|
8
|
-
network: solana
|
|
9
|
-
addresses:
|
|
10
|
-
- 2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S # binance
|
|
11
|
-
|
|
12
|
-
- ticker: BTC
|
|
13
|
-
network: bitcoin
|
|
14
|
-
comment: coldwallets
|
|
15
|
-
addresses: |
|
|
16
|
-
34xp4vRoCGJym3xR7yCVPFHoCNxv4Twseo # binance
|
|
17
|
-
bc1qgdjqv0av3q56jvd82tkdjpy7gdp9ut8tlqmgrpmv24sq90ecnvqqjwvw97 # bitfinex
|
|
18
|
-
bc1ql49ydapnjafl5t2cp9zqpjwe6pdgmxy98859v2 # robinhood
|
|
19
|
-
share: 0.1 # 10%
|
|
20
|
-
|
|
21
|
-
- ticker: ETH
|
|
22
|
-
network: ethereum
|
|
23
|
-
comment: okx
|
|
24
|
-
addresses: okx_eth
|
|
25
|
-
|
|
26
|
-
- ticker: USDT
|
|
27
|
-
network: ethereum
|
|
28
|
-
comment: okx
|
|
29
|
-
addresses: okx_eth
|
|
30
|
-
|
|
31
|
-
- ticker: ETH
|
|
32
|
-
network: ethereum
|
|
33
|
-
comment: binance
|
|
34
|
-
addresses: binance_eth
|
|
35
|
-
|
|
36
|
-
- ticker: USDT
|
|
37
|
-
network: ethereum
|
|
38
|
-
comment: binance
|
|
39
|
-
addresses: binance_eth
|
|
40
|
-
|
|
41
|
-
- ticker: USDC
|
|
42
|
-
comment: swap.thala.apt
|
|
43
|
-
network: aptos
|
|
44
|
-
token_address: 0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC
|
|
45
|
-
token_decimals: 6
|
|
46
|
-
addresses: "0x48271d39d0b05bd6efca2278f22277d6fcc375504f9839fd73f74ace240861af" # for a single line it's necessary to use quotes
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
addresses:
|
|
50
|
-
- name: okx_eth
|
|
51
|
-
addresses: |
|
|
52
|
-
0xf59869753f41db720127ceb8dbb8afaf89030de4
|
|
53
|
-
0x65a0947ba5175359bb457d3b34491edf4cbf7997
|
|
54
|
-
0xe9172daf64b05b26eb18f07ac8d6d723acb48f99
|
|
55
|
-
0x4d19c0a5357bc48be0017095d3c871d9afc3f21d
|
|
56
|
-
|
|
57
|
-
- name: binance_eth
|
|
58
|
-
addresses: |
|
|
59
|
-
0xf977814e90da44bfa03b6295a0616a897441acec
|
|
60
|
-
0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503
|
|
61
|
-
|
|
62
|
-
##Optional settings:
|
|
63
|
-
#proxies_url: https://site.com/api/proxies # get proxies from this url
|
|
64
|
-
#proxies:
|
|
65
|
-
#- http://123.123.123.121
|
|
66
|
-
#- http://123.123.123.122
|
|
67
|
-
#- http://123.123.123.123
|
|
68
|
-
#- http://123.123.123.124
|
|
69
|
-
#round_ndigits: 4
|
|
70
|
-
#price: yes
|
|
71
|
-
#skip_empty: no
|
|
72
|
-
#print_debug: no
|
|
73
|
-
#print_format: table # table, json
|
|
74
|
-
#format_number_separator: ","
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
mm_balance/cli.py,sha256=7yQ0DiSDVYeG9lFav-PJnVswncWIfpZsj1G7CZvMDmc,3119
|
|
3
|
-
mm_balance/config.py,sha256=LsmfluUFpTfXMvXUUzGQtiZlz1gliiDrDx4c4SqgPws,5383
|
|
4
|
-
mm_balance/constants.py,sha256=kqG2zuwv0l-PzDHIrMJVQpfQWiXjr2DsqGPcKmqNJLo,2334
|
|
5
|
-
mm_balance/price.py,sha256=9pK2Iy44zTcHIlrja5wC_jV03Q7bJr-S8joNzEsyUl0,1485
|
|
6
|
-
mm_balance/result.py,sha256=rwCSnuyK-u4mz1QmQucFKLC2-vpkSoXfFxbu0MScp9g,4524
|
|
7
|
-
mm_balance/token_decimals.py,sha256=5VZyx29euGtE2KIStQjh6xCcVg1qQweFAykUZU6vkRU,2268
|
|
8
|
-
mm_balance/utils.py,sha256=bngYS2WFIakGZO31_ey4MPsllvDhgOxkAnGiXqom3J4,286
|
|
9
|
-
mm_balance/workers.py,sha256=HujTVy_XxXbFLnZdLh1RjN0q9ziwaRRrQspffBSSLQU,3795
|
|
10
|
-
mm_balance/config/example.yml,sha256=7n72tHsnUbZ64q856IeKHlmt-7PvtAgZlB8t4AS0NzI,1899
|
|
11
|
-
mm_balance/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
mm_balance/output/utils.py,sha256=WUFwshFMKZKdcwRtO21nhxqW78JeLAatDyHPZhdV96A,716
|
|
13
|
-
mm_balance/output/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
mm_balance/output/formats/json_format.py,sha256=yMkZTA6vOUpLSixF7H4H4lVZKShRs4B9qmUR8L-CRvw,866
|
|
15
|
-
mm_balance/output/formats/table_format.py,sha256=qN1uMF1cyAVOH31Gohoc_a4l9-pWTSZ8WRxBBSAwj54,4539
|
|
16
|
-
mm_balance/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
mm_balance/rpc/aptos.py,sha256=1JCYCqDim4tk1axXscaAJRXPd4J6vV1ABFbwMbPgrL0,641
|
|
18
|
-
mm_balance/rpc/btc.py,sha256=ugp90H7YW0kiXIh98bQWk9mQTW20yE-jBiCpRvfoH-U,481
|
|
19
|
-
mm_balance/rpc/evm.py,sha256=ewlMmRrcXKlky3DPNbnUBTVwnvyw7N9iCZLsCX2V14w,1007
|
|
20
|
-
mm_balance/rpc/solana.py,sha256=Lwl5Otqy48g4LWfz9uN7_rkICKUIYJvf88PbIAnfMdc,1051
|
|
21
|
-
mm_balance-0.1.19.dist-info/METADATA,sha256=V4gmUFJZqkwrVTWctBPk0Ocs8sZ4xRMw3dUhDKn_i6o,229
|
|
22
|
-
mm_balance-0.1.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
23
|
-
mm_balance-0.1.19.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
|
|
24
|
-
mm_balance-0.1.19.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|