mm-balance 0.1.10__py3-none-any.whl → 0.1.11__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/balances.py +2 -2
- mm_balance/cli.py +2 -1
- mm_balance/config/example.yml +2 -2
- mm_balance/config.py +62 -69
- mm_balance/{types.py → constants.py} +19 -12
- mm_balance/output.py +2 -2
- mm_balance/price.py +15 -43
- mm_balance/rpc/btc.py +5 -9
- mm_balance/rpc/eth.py +6 -21
- mm_balance/rpc/solana.py +11 -7
- mm_balance/token_decimals.py +1 -1
- mm_balance/total.py +1 -1
- {mm_balance-0.1.10.dist-info → mm_balance-0.1.11.dist-info}/METADATA +1 -1
- mm_balance-0.1.11.dist-info/RECORD +18 -0
- mm_balance-0.1.10.dist-info/RECORD +0 -18
- {mm_balance-0.1.10.dist-info → mm_balance-0.1.11.dist-info}/WHEEL +0 -0
- {mm_balance-0.1.10.dist-info → mm_balance-0.1.11.dist-info}/entry_points.txt +0 -0
mm_balance/balances.py
CHANGED
|
@@ -8,9 +8,9 @@ from rich.progress import TaskID
|
|
|
8
8
|
|
|
9
9
|
from mm_balance import output
|
|
10
10
|
from mm_balance.config import Config
|
|
11
|
+
from mm_balance.constants import Network
|
|
11
12
|
from mm_balance.rpc import btc, eth, solana
|
|
12
13
|
from mm_balance.token_decimals import TokenDecimals
|
|
13
|
-
from mm_balance.types import Network
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class Balances:
|
|
@@ -58,7 +58,7 @@ class Balances:
|
|
|
58
58
|
token_decimals = self.token_decimals[network][token_address] if token_address else -1
|
|
59
59
|
match network:
|
|
60
60
|
case Network.BTC:
|
|
61
|
-
res = btc.get_balance(wallet_address,
|
|
61
|
+
res = btc.get_balance(wallet_address, proxies, round_ndigits)
|
|
62
62
|
case Network.ETH:
|
|
63
63
|
if token_address is None:
|
|
64
64
|
res = eth.get_native_balance(nodes, wallet_address, proxies, round_ndigits)
|
mm_balance/cli.py
CHANGED
|
@@ -32,11 +32,12 @@ def cli(
|
|
|
32
32
|
config = Config.read_config(config_path, zip_password=zip_password)
|
|
33
33
|
|
|
34
34
|
prices = get_prices(config) if config.price else Prices()
|
|
35
|
+
output.print_prices(config, prices)
|
|
36
|
+
|
|
35
37
|
token_decimals = get_token_decimals(config)
|
|
36
38
|
balances = Balances(config, token_decimals)
|
|
37
39
|
balances.process()
|
|
38
40
|
|
|
39
|
-
output.print_prices(config, prices)
|
|
40
41
|
output.print_groups(balances, config, prices)
|
|
41
42
|
output.print_total(config, balances, prices)
|
|
42
43
|
|
mm_balance/config/example.yml
CHANGED
mm_balance/config.py
CHANGED
|
@@ -7,67 +7,69 @@ import pydash
|
|
|
7
7
|
from mm_std import BaseConfig, PrintFormat, fatal, hr
|
|
8
8
|
from pydantic import Field, field_validator, model_validator
|
|
9
9
|
|
|
10
|
-
from mm_balance.
|
|
10
|
+
from mm_balance.constants import DEFAULT_ETH_NODES, DEFAULT_SOL_NODES, EthTokenAddress, Network, SolTokenAddress
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Group(BaseConfig):
|
|
14
|
+
comment: str = ""
|
|
15
|
+
coin: str
|
|
16
|
+
network: Network
|
|
17
|
+
token_address: str | None = None
|
|
18
|
+
coingecko_id: str | None = None
|
|
19
|
+
addresses: list[str] = Field(default_factory=list)
|
|
20
|
+
share: Decimal = Decimal(1)
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def name(self) -> str:
|
|
24
|
+
result = self.coin
|
|
25
|
+
if self.comment:
|
|
26
|
+
result += " / " + self.comment
|
|
27
|
+
return result
|
|
28
|
+
|
|
29
|
+
@field_validator("coin", mode="after")
|
|
30
|
+
def coin_validator(cls, v: str) -> str:
|
|
31
|
+
return v.upper()
|
|
32
|
+
|
|
33
|
+
@field_validator("addresses", mode="before")
|
|
34
|
+
def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
|
|
35
|
+
return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
|
|
36
|
+
|
|
37
|
+
@model_validator(mode="before")
|
|
38
|
+
def before_all(cls, data: Any) -> Any:
|
|
39
|
+
if "network" not in data:
|
|
40
|
+
data["network"] = detect_network(data["coin"])
|
|
41
|
+
return data
|
|
42
|
+
|
|
43
|
+
@model_validator(mode="after")
|
|
44
|
+
def final_validator(self) -> Self:
|
|
45
|
+
if self.token_address is None:
|
|
46
|
+
self.token_address = detect_token_address(self.coin, self.network)
|
|
47
|
+
if self.token_address is not None and self.network is Network.ETH:
|
|
48
|
+
self.token_address = self.token_address.lower()
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def process_addresses(self, address_groups: list[AddressGroup]) -> None:
|
|
52
|
+
addresses: list[str] = []
|
|
53
|
+
for address in self.addresses:
|
|
54
|
+
if address_group := pydash.find(address_groups, lambda g: g.name == address): # noqa: B023
|
|
55
|
+
addresses.extend(address_group.addresses)
|
|
56
|
+
else:
|
|
57
|
+
# TODO: check address is valid
|
|
58
|
+
addresses.append(address)
|
|
59
|
+
self.addresses = addresses
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class AddressGroup(BaseConfig):
|
|
63
|
+
name: str
|
|
64
|
+
addresses: list[str]
|
|
65
|
+
|
|
66
|
+
@field_validator("addresses", mode="before")
|
|
67
|
+
def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
|
|
68
|
+
return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
|
|
11
69
|
|
|
12
70
|
|
|
13
71
|
class Config(BaseConfig):
|
|
14
|
-
|
|
15
|
-
comment: str = ""
|
|
16
|
-
coin: str
|
|
17
|
-
network: Network
|
|
18
|
-
token_address: str | None = None
|
|
19
|
-
coingecko_id: str | None = None
|
|
20
|
-
addresses: list[str] = Field(default_factory=list)
|
|
21
|
-
share: Decimal = Decimal(1)
|
|
22
|
-
|
|
23
|
-
@property
|
|
24
|
-
def name(self) -> str:
|
|
25
|
-
result = self.coin
|
|
26
|
-
if self.comment:
|
|
27
|
-
result += " / " + self.comment
|
|
28
|
-
return result
|
|
29
|
-
|
|
30
|
-
@field_validator("coin", mode="after")
|
|
31
|
-
def coin_validator(cls, v: str) -> str:
|
|
32
|
-
return v.upper()
|
|
33
|
-
|
|
34
|
-
@field_validator("addresses", mode="before")
|
|
35
|
-
def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
|
|
36
|
-
return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
|
|
37
|
-
|
|
38
|
-
@model_validator(mode="before")
|
|
39
|
-
def before_all(cls, data: Any) -> Any:
|
|
40
|
-
if "network" not in data:
|
|
41
|
-
data["network"] = detect_network(data["coin"])
|
|
42
|
-
return data
|
|
43
|
-
|
|
44
|
-
@model_validator(mode="after")
|
|
45
|
-
def final_validator(self) -> Self:
|
|
46
|
-
if self.token_address is None:
|
|
47
|
-
self.token_address = detect_token_address(self.coin, self.network)
|
|
48
|
-
if self.token_address is not None and self.network is Network.ETH:
|
|
49
|
-
self.token_address = self.token_address.lower()
|
|
50
|
-
return self
|
|
51
|
-
|
|
52
|
-
def process_addresses(self, address_groups: list[Config.AddressGroup]) -> None:
|
|
53
|
-
addresses: list[str] = []
|
|
54
|
-
for address in self.addresses:
|
|
55
|
-
if address_group := pydash.find(address_groups, lambda g: g.name == address): # noqa: B023
|
|
56
|
-
addresses.extend(address_group.addresses)
|
|
57
|
-
else:
|
|
58
|
-
# TODO: check address is valid
|
|
59
|
-
addresses.append(address)
|
|
60
|
-
self.addresses = addresses
|
|
61
|
-
|
|
62
|
-
class AddressGroup(BaseConfig):
|
|
63
|
-
name: str
|
|
64
|
-
addresses: list[str]
|
|
65
|
-
|
|
66
|
-
@field_validator("addresses", mode="before")
|
|
67
|
-
def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
|
|
68
|
-
return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
|
|
69
|
-
|
|
70
|
-
groups: list[Group]
|
|
72
|
+
groups: list[Group] = Field(alias="coins")
|
|
71
73
|
addresses: list[AddressGroup] = Field(default_factory=list)
|
|
72
74
|
|
|
73
75
|
proxies_url: str | None = None
|
|
@@ -79,15 +81,6 @@ class Config(BaseConfig):
|
|
|
79
81
|
|
|
80
82
|
workers: dict[Network, int] = {network: 5 for network in Network}
|
|
81
83
|
|
|
82
|
-
def btc_groups(self) -> list[Group]:
|
|
83
|
-
return [g for g in self.groups if g.network == Network.BTC]
|
|
84
|
-
|
|
85
|
-
def eth_groups(self) -> list[Group]:
|
|
86
|
-
return [g for g in self.groups if g.network == Network.ETH]
|
|
87
|
-
|
|
88
|
-
def sol_groups(self) -> list[Group]:
|
|
89
|
-
return [g for g in self.groups if g.network == Network.SOL]
|
|
90
|
-
|
|
91
84
|
def has_share(self) -> bool:
|
|
92
85
|
return any(g.share != Decimal(1) for g in self.groups)
|
|
93
86
|
|
|
@@ -121,7 +114,7 @@ def detect_network(coin: str) -> Network:
|
|
|
121
114
|
if coin == "sol":
|
|
122
115
|
return Network.SOL
|
|
123
116
|
return Network.ETH
|
|
124
|
-
# raise ValueError(f"can't get network for the coin: {coin}")
|
|
117
|
+
# TODO: raise ValueError(f"can't get network for the coin: {coin}")
|
|
125
118
|
|
|
126
119
|
|
|
127
120
|
def detect_token_address(coin: str, network: str) -> str | None:
|
|
@@ -149,5 +142,5 @@ def get_proxies(proxies_url: str) -> list[str]:
|
|
|
149
142
|
fatal(f"Can't get proxies: {err}")
|
|
150
143
|
|
|
151
144
|
|
|
152
|
-
def get_address_group_by_name(address_groups: list[
|
|
145
|
+
def get_address_group_by_name(address_groups: list[AddressGroup], name: str) -> AddressGroup | None:
|
|
153
146
|
return pydash.find(address_groups, lambda g: g.name == name)
|
|
@@ -2,6 +2,25 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from enum import Enum, unique
|
|
4
4
|
|
|
5
|
+
RETRIES_BALANCE = 5
|
|
6
|
+
RETRIES_DECIMALS = 5
|
|
7
|
+
RETRIES_COINGECKO_PRICES = 5
|
|
8
|
+
TIMEOUT_BALANCE = 5
|
|
9
|
+
TIMEOUT_DECIMALS = 5
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@unique
|
|
13
|
+
class EthTokenAddress(str, Enum):
|
|
14
|
+
USDT = "0xdac17f958d2ee523a2206206994597c13d831ec7"
|
|
15
|
+
USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@unique
|
|
19
|
+
class SolTokenAddress(str, Enum):
|
|
20
|
+
USDT = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
|
|
21
|
+
USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
|
|
22
|
+
|
|
23
|
+
|
|
5
24
|
DEFAULT_ETH_NODES = ["https://ethereum.publicnode.com", "https://rpc.ankr.com/eth"]
|
|
6
25
|
DEFAULT_SOL_NODES = ["https://api.mainnet-beta.solana.com"]
|
|
7
26
|
|
|
@@ -24,15 +43,3 @@ class Network(str, Enum):
|
|
|
24
43
|
BTC = "btc"
|
|
25
44
|
ETH = "eth"
|
|
26
45
|
SOL = "sol"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@unique
|
|
30
|
-
class EthTokenAddress(str, Enum):
|
|
31
|
-
USDT = "0xdac17f958d2ee523a2206206994597c13d831ec7"
|
|
32
|
-
USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@unique
|
|
36
|
-
class SolTokenAddress(str, Enum):
|
|
37
|
-
USDT = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
|
|
38
|
-
USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
|
mm_balance/output.py
CHANGED
|
@@ -4,7 +4,7 @@ from mm_std import Ok, print_table
|
|
|
4
4
|
from rich.progress import BarColumn, MofNCompleteColumn, Progress, TaskID, TextColumn
|
|
5
5
|
|
|
6
6
|
from mm_balance.balances import Balances
|
|
7
|
-
from mm_balance.config import Config
|
|
7
|
+
from mm_balance.config import Config, Group
|
|
8
8
|
from mm_balance.price import Prices
|
|
9
9
|
from mm_balance.total import Total
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ def print_groups(balances: Balances, config: Config, prices: Prices) -> None:
|
|
|
15
15
|
_print_group(group, group_balances, config, prices)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def _print_group(group:
|
|
18
|
+
def _print_group(group: Group, group_balances: list[Balances.Balance], config: Config, prices: Prices) -> None:
|
|
19
19
|
rows = []
|
|
20
20
|
balance_sum = Decimal(0)
|
|
21
21
|
usd_sum = Decimal(0)
|
mm_balance/price.py
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import time
|
|
2
1
|
from decimal import Decimal
|
|
3
2
|
|
|
4
3
|
import pydash
|
|
5
|
-
from mm_std import
|
|
4
|
+
from mm_std import fatal, hr
|
|
6
5
|
from mm_std.random_ import random_str_choice
|
|
7
6
|
|
|
8
|
-
from mm_balance import
|
|
9
|
-
from mm_balance.
|
|
10
|
-
from mm_balance.types import EthTokenAddress, Network
|
|
7
|
+
from mm_balance.config import Config, Group
|
|
8
|
+
from mm_balance.constants import RETRIES_COINGECKO_PRICES, EthTokenAddress, Network
|
|
11
9
|
|
|
12
10
|
|
|
13
11
|
class Prices(dict[str, Decimal]):
|
|
@@ -21,52 +19,26 @@ class Prices(dict[str, Decimal]):
|
|
|
21
19
|
|
|
22
20
|
def get_prices(config: Config) -> Prices:
|
|
23
21
|
result = Prices()
|
|
24
|
-
coins_total = len(pydash.uniq([group.coin for group in config.groups]))
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
coins = pydash.uniq([group.coin for group in config.groups])
|
|
24
|
+
coingecko_ids = pydash.uniq([get_coingecko_id(group) for group in config.groups])
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
url = f"https://api.coingecko.com/api/v3/simple/price?ids={",".join(coingecko_ids)}&vs_currencies=usd"
|
|
27
|
+
for _ in range(RETRIES_COINGECKO_PRICES):
|
|
28
|
+
res = hr(url, proxy=random_str_choice(config.proxies))
|
|
29
|
+
if res.code != 200:
|
|
30
|
+
continue
|
|
30
31
|
|
|
31
|
-
for
|
|
32
|
-
if
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
coingecko_id = get_coingecko_id(group)
|
|
36
|
-
res = get_asset_price(coingecko_id, config.proxies)
|
|
37
|
-
if isinstance(res, Ok):
|
|
38
|
-
result[group.coin] = res.ok
|
|
39
|
-
progress.update(task_id, advance=1)
|
|
32
|
+
for idx, coin in enumerate(coins):
|
|
33
|
+
if coingecko_ids[idx] in res.json:
|
|
34
|
+
result[coin] = Decimal(str(pydash.get(res.json, f"{coingecko_ids[idx]}.usd")))
|
|
40
35
|
else:
|
|
41
|
-
fatal(
|
|
42
|
-
# raise ValueError(res.err)
|
|
36
|
+
fatal("Can't get price for {coin} from coingecko, coingecko_id={coingecko_ids[idx]}")
|
|
43
37
|
|
|
44
38
|
return result
|
|
45
39
|
|
|
46
40
|
|
|
47
|
-
def
|
|
48
|
-
url = f"https://api.coingecko.com/api/v3/simple/price?ids={coingecko_asset_id}&vs_currencies=usd"
|
|
49
|
-
data = None
|
|
50
|
-
error = f"error: can't get price for {coingecko_asset_id} from coingecko"
|
|
51
|
-
for _ in range(3):
|
|
52
|
-
res = hr(url, proxy=random_str_choice(proxies))
|
|
53
|
-
|
|
54
|
-
# Check for Rate Limit
|
|
55
|
-
if res.code == 429:
|
|
56
|
-
error = f"error: can't get price for {coingecko_asset_id} from coingecko. You've exceeded the Rate Limit. Please add more proxies." # noqa: E501
|
|
57
|
-
if not proxies:
|
|
58
|
-
fatal(error) # Exit immidiately if no proxies are provided
|
|
59
|
-
|
|
60
|
-
data = res.to_dict()
|
|
61
|
-
if res.json and coingecko_asset_id in coingecko_asset_id in res.json:
|
|
62
|
-
return Ok(Decimal(pydash.get(res.json, f"{coingecko_asset_id}.usd")))
|
|
63
|
-
|
|
64
|
-
if not proxies:
|
|
65
|
-
time.sleep(10)
|
|
66
|
-
return Err(error, data=data)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def get_coingecko_id(group: Config.Group) -> str:
|
|
41
|
+
def get_coingecko_id(group: Group) -> str:
|
|
70
42
|
if group.coingecko_id:
|
|
71
43
|
return group.coingecko_id
|
|
72
44
|
elif group.network is Network.BTC:
|
mm_balance/rpc/btc.py
CHANGED
|
@@ -2,19 +2,15 @@ from decimal import Decimal
|
|
|
2
2
|
|
|
3
3
|
from mm_btc.blockstream import BlockstreamClient
|
|
4
4
|
from mm_std import Ok, Result
|
|
5
|
-
from rich.progress import Progress, TaskID
|
|
6
5
|
|
|
7
|
-
from mm_balance.
|
|
6
|
+
from mm_balance.constants import RETRIES_BALANCE
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
def get_balance(address: str,
|
|
11
|
-
|
|
12
|
-
BlockstreamClient(proxies=
|
|
9
|
+
def get_balance(address: str, proxies: list[str], round_ndigits: int) -> Result[Decimal]:
|
|
10
|
+
return (
|
|
11
|
+
BlockstreamClient(proxies=proxies, attempts=RETRIES_BALANCE)
|
|
13
12
|
.get_confirmed_balance(address)
|
|
14
13
|
.and_then(
|
|
15
|
-
lambda b: Ok(round(Decimal(b / 100_000_000),
|
|
14
|
+
lambda b: Ok(round(Decimal(b / 100_000_000), round_ndigits)),
|
|
16
15
|
)
|
|
17
16
|
)
|
|
18
|
-
if task_id is not None and progress is not None:
|
|
19
|
-
progress.update(task_id, advance=1)
|
|
20
|
-
return res
|
mm_balance/rpc/eth.py
CHANGED
|
@@ -3,9 +3,11 @@ from decimal import Decimal
|
|
|
3
3
|
from mm_eth import erc20, rpc
|
|
4
4
|
from mm_std import Ok, Result
|
|
5
5
|
|
|
6
|
+
from mm_balance.constants import RETRIES_BALANCE, RETRIES_DECIMALS, TIMEOUT_BALANCE, TIMEOUT_DECIMALS
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
def get_native_balance(nodes: list[str], address: str, proxies: list[str], round_ndigits: int) -> Result[Decimal]:
|
|
8
|
-
return rpc.eth_get_balance(nodes, address, proxies=proxies, attempts=
|
|
10
|
+
return rpc.eth_get_balance(nodes, address, proxies=proxies, attempts=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE).and_then(
|
|
9
11
|
lambda b: Ok(round(Decimal(b / 10**18), round_ndigits)),
|
|
10
12
|
)
|
|
11
13
|
|
|
@@ -18,29 +20,12 @@ def get_token_balance(
|
|
|
18
20
|
token_address,
|
|
19
21
|
wallet_address,
|
|
20
22
|
proxies=proxies,
|
|
21
|
-
attempts=
|
|
22
|
-
timeout=
|
|
23
|
+
attempts=RETRIES_BALANCE,
|
|
24
|
+
timeout=TIMEOUT_BALANCE,
|
|
23
25
|
).and_then(
|
|
24
26
|
lambda b: Ok(round(Decimal(b / 10**decimals), round_ndigits)),
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
|
|
29
|
-
return erc20.get_decimals(nodes, token_address, timeout=
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# def get_balance(
|
|
33
|
-
# address: str, token_address: str | None, config: Config, progress: Progress | None = None, task_id: TaskID | None = None
|
|
34
|
-
# ) -> Result[Decimal]:
|
|
35
|
-
# res: Result[Decimal]
|
|
36
|
-
#
|
|
37
|
-
# if token_address is not None:
|
|
38
|
-
#
|
|
39
|
-
# else:
|
|
40
|
-
# res = rpc.eth_get_balance(config.nodes[Network.ETH], address, proxies=config.proxies, attempts=5, timeout=10).and_then(
|
|
41
|
-
# lambda b: Ok(round(Decimal(b / 10 ** 18), config.round_ndigits)),
|
|
42
|
-
# )
|
|
43
|
-
#
|
|
44
|
-
# if task_id is not None and progress is not None:
|
|
45
|
-
# progress.update(task_id, advance=1)
|
|
46
|
-
# return res
|
|
31
|
+
return erc20.get_decimals(nodes, token_address, timeout=TIMEOUT_DECIMALS, proxies=proxies, attempts=RETRIES_DECIMALS)
|
mm_balance/rpc/solana.py
CHANGED
|
@@ -3,20 +3,24 @@ from decimal import Decimal
|
|
|
3
3
|
from mm_solana import balance, token
|
|
4
4
|
from mm_std import Ok, Result
|
|
5
5
|
|
|
6
|
+
from mm_balance.constants import RETRIES_BALANCE, RETRIES_DECIMALS, TIMEOUT_BALANCE, TIMEOUT_DECIMALS
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
def get_native_balance(nodes: list[str], address: str, proxies: list[str], round_ndigits: int) -> Result[Decimal]:
|
|
8
|
-
return balance.get_balance_with_retries(
|
|
9
|
-
|
|
10
|
-
)
|
|
10
|
+
return balance.get_balance_with_retries(
|
|
11
|
+
nodes, address, retries=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE, proxies=proxies
|
|
12
|
+
).and_then(lambda b: Ok(round(Decimal(b / 1_000_000_000), round_ndigits)))
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def get_token_balance(
|
|
14
16
|
nodes: list[str], wallet_address: str, token_address: str, decimals: int, proxies: list[str], round_ndigits: int
|
|
15
17
|
) -> Result[Decimal]:
|
|
16
|
-
return token.get_balance_with_retries(
|
|
17
|
-
|
|
18
|
-
)
|
|
18
|
+
return token.get_balance_with_retries(
|
|
19
|
+
nodes, wallet_address, token_address, retries=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE, proxies=proxies
|
|
20
|
+
).and_then(lambda b: Ok(round(Decimal(b / 10**decimals), round_ndigits)))
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
|
|
22
|
-
return token.get_decimals_with_retries(
|
|
24
|
+
return token.get_decimals_with_retries(
|
|
25
|
+
nodes, token_address, retries=RETRIES_DECIMALS, timeout=TIMEOUT_DECIMALS, proxies=proxies
|
|
26
|
+
)
|
mm_balance/token_decimals.py
CHANGED
mm_balance/total.py
CHANGED
|
@@ -7,8 +7,8 @@ from mm_std import Ok, PrintFormat, print_table
|
|
|
7
7
|
|
|
8
8
|
from mm_balance.balances import Balances
|
|
9
9
|
from mm_balance.config import Config
|
|
10
|
+
from mm_balance.constants import Coin
|
|
10
11
|
from mm_balance.price import Prices
|
|
11
|
-
from mm_balance.types import Coin
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@dataclass
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
mm_balance/balances.py,sha256=fawnQIfjWsljXo1MdvSxs3Xo7j19hBCa9jlyDXXWO7M,7587
|
|
3
|
+
mm_balance/cli.py,sha256=tjMXQhtKZiCzqoTw5rIygMaVCOwNMiNbkr4nzOY06wA,1360
|
|
4
|
+
mm_balance/config.py,sha256=lDizIS2qmZpiOWbrdPvn0DKUdN0FWuNdv2qKPJBfWEI,4866
|
|
5
|
+
mm_balance/constants.py,sha256=GnyqtIfxIpWLuzB80Y0mYrzrRk8XT3fMHh63Fek5LEA,935
|
|
6
|
+
mm_balance/output.py,sha256=GH5ESychKEDOc2gtaUH_JtKdNX1ZkXZD6kCk2mxd8_4,2568
|
|
7
|
+
mm_balance/price.py,sha256=uAm7pVAwMyzZ7bE4xxz4PD0mzLR7zFk6UtYSwGqWjAs,1996
|
|
8
|
+
mm_balance/token_decimals.py,sha256=8tAZiN5RpSFRtYb1VODABGg9x3JbLY73EA5BV0RqVv4,1297
|
|
9
|
+
mm_balance/total.py,sha256=3IDNBrcqGFaUYMlAzLpQCEBcWi1zdT0RSm7o7t1b4Tw,4700
|
|
10
|
+
mm_balance/config/example.yml,sha256=j3UzCgCIImkkzyMT_68LW7lRChsQOlwowhKjcwRBlyc,1336
|
|
11
|
+
mm_balance/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
mm_balance/rpc/btc.py,sha256=ugp90H7YW0kiXIh98bQWk9mQTW20yE-jBiCpRvfoH-U,481
|
|
13
|
+
mm_balance/rpc/eth.py,sha256=G7aYjTw6xJwcsAyIp9eVW8NRVDUGeTCpdbd-CqgqHyw,1167
|
|
14
|
+
mm_balance/rpc/solana.py,sha256=vmCAaeQKwxg95qdSmUEjFS9bAPUJVx8irtWv6nlRBvU,1174
|
|
15
|
+
mm_balance-0.1.11.dist-info/METADATA,sha256=ExgagHu4tCqpAHPjqivCaQ7-2Dj3HwrwOeyJct7DsXw,198
|
|
16
|
+
mm_balance-0.1.11.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
17
|
+
mm_balance-0.1.11.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
|
|
18
|
+
mm_balance-0.1.11.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
mm_balance/balances.py,sha256=iERBZ_kTqj1wSlwUv5O2OteEhK2FMttD8Enx2avQHm0,7572
|
|
3
|
-
mm_balance/cli.py,sha256=qKmupsRR3dGKZzA5hrKgmd4N4SoRMKTI8HAiwhSvgXI,1359
|
|
4
|
-
mm_balance/config.py,sha256=n6NbsgnB-Uus4kOZJr37n7BnHc539LH8LT6BpJbqhVU,5370
|
|
5
|
-
mm_balance/output.py,sha256=Sb0pccEBNOCR9fuMigO9GJcyTNw9XPRZXTg8iznJKFQ,2568
|
|
6
|
-
mm_balance/price.py,sha256=KyMx1T57SczKbYmbghpGty9BrPebrZdjBW0_BaabKDk,2926
|
|
7
|
-
mm_balance/token_decimals.py,sha256=UlYzLFR_w-jAsotq8CjGJc38KwklWG0Tr0JK-_wK6QQ,1293
|
|
8
|
-
mm_balance/total.py,sha256=OuXfKKy18X9f7HO_RJNFh4M8VPVH0MBb3soSRsqS_RY,4696
|
|
9
|
-
mm_balance/types.py,sha256=O6mjf2UYSl2XzwMU8Zsg_T2iYdSxZPg2-7UV1UORaMU,822
|
|
10
|
-
mm_balance/config/example.yml,sha256=A3pGt8BVykKNajfhHziTM7RLM1KSZOm_kmhCQExQkgo,1336
|
|
11
|
-
mm_balance/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
mm_balance/rpc/btc.py,sha256=OozGSF8CzR13jxTYjvBqkC8d0pdKkyEHxM7e7M_WbV0,681
|
|
13
|
-
mm_balance/rpc/eth.py,sha256=vWjgvP2P_ejwK_dsxS3NZCP0PJyLFDndvfVaZIePXOU,1578
|
|
14
|
-
mm_balance/rpc/solana.py,sha256=NIa494HjvHYONutKV_6HGcJV5tqiRvA1099JVkrrdd8,972
|
|
15
|
-
mm_balance-0.1.10.dist-info/METADATA,sha256=fDZjEFqUMNBwhqwoyG0ldd65jlV2EEqnKhZ00PynqN0,198
|
|
16
|
-
mm_balance-0.1.10.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
|
17
|
-
mm_balance-0.1.10.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
|
|
18
|
-
mm_balance-0.1.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|