mm-balance 0.1.8__py3-none-any.whl → 0.1.10__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 CHANGED
@@ -4,88 +4,166 @@ from decimal import Decimal
4
4
 
5
5
  from mm_std import ConcurrentTasks, Result
6
6
  from pydantic import BaseModel
7
+ from rich.progress import TaskID
7
8
 
8
- from mm_balance import btc, eth, solana
9
+ from mm_balance import output
9
10
  from mm_balance.config import Config
11
+ from mm_balance.rpc import btc, eth, solana
12
+ from mm_balance.token_decimals import TokenDecimals
10
13
  from mm_balance.types import Network
11
14
 
12
15
 
13
- class Balances(BaseModel):
16
+ class Balances:
14
17
  class Balance(BaseModel):
15
18
  group_index: int
16
19
  address: str
17
20
  token_address: str | None
18
21
  balance: Result[Decimal] | None = None
19
22
 
20
- config: Config
21
- # separate balance tasks on networks
22
- btc: list[Balance]
23
- eth: list[Balance]
24
- sol: list[Balance]
25
-
26
- def network_tasks(self, network: Network) -> list[Balance]:
27
- if network == Network.BTC:
28
- return self.btc
29
- elif network == Network.ETH:
30
- return self.eth
31
- elif network == Network.SOL:
32
- return self.sol
33
- else:
34
- raise ValueError
23
+ def __init__(self, config: Config, token_decimals: TokenDecimals):
24
+ self.config = config
25
+ self.token_decimals = token_decimals
26
+ self.tasks: dict[Network, list[Balances.Balance]] = {network: [] for network in Network}
27
+ self.progress_bar = output.create_progress_bar()
28
+ self.progress_bar_task: dict[Network, TaskID] = {}
35
29
 
36
- def get_group_balances(self, group_index: int, network: Network) -> list[Balance]:
37
- # TODO: can we get network by group_index?
38
- if network == Network.BTC:
39
- network_balances = self.btc
40
- elif network == Network.ETH:
41
- network_balances = self.eth
42
- elif network == Network.SOL:
43
- network_balances = self.sol
44
- else:
45
- raise ValueError
30
+ for idx, group in enumerate(config.groups):
31
+ task_list = [Balances.Balance(group_index=idx, address=a, token_address=group.token_address) for a in group.addresses]
32
+ self.tasks[group.network].extend(task_list)
46
33
 
47
- return [b for b in network_balances if b.group_index == group_index]
34
+ for network in Network:
35
+ self.progress_bar_task[network] = output.create_progress_task(
36
+ self.progress_bar, network.value, len(self.tasks[network])
37
+ )
48
38
 
49
39
  def process(self) -> None:
50
- job = ConcurrentTasks()
51
- job.add_task("btc", self._process_btc)
52
- job.add_task("eth", self._process_eth)
53
- job.add_task("sol", self._process_sol)
54
- job.execute()
40
+ with self.progress_bar:
41
+ job = ConcurrentTasks(max_workers=10)
42
+ for network in Network:
43
+ job.add_task(network.value, self._process_network, args=(network,))
44
+ job.execute()
55
45
 
56
- def _process_btc(self) -> None:
57
- job = ConcurrentTasks(max_workers=self.config.workers.btc)
58
- for idx, task in enumerate(self.btc):
59
- job.add_task(str(idx), btc.get_balance, args=(task.address, self.config))
46
+ def _process_network(self, network: Network) -> None:
47
+ job = ConcurrentTasks(max_workers=self.config.workers[network])
48
+ for idx, task in enumerate(self.tasks[network]):
49
+ job.add_task(str(idx), self._get_balance, args=(network, task.address, task.token_address))
60
50
  job.execute()
61
- for idx, _task in enumerate(self.btc):
62
- self.btc[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
51
+ for idx, _task in enumerate(self.tasks[network]):
52
+ self.tasks[network][idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
63
53
 
64
- def _process_eth(self) -> None:
65
- job = ConcurrentTasks(max_workers=self.config.workers.eth)
66
- for idx, task in enumerate(self.eth):
67
- job.add_task(str(idx), eth.get_balance, args=(task.address, task.token_address, self.config))
68
- job.execute()
69
- for idx, _task in enumerate(self.eth):
70
- self.eth[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
54
+ def _get_balance(self, network: Network, wallet_address: str, token_address: str | None) -> Result[Decimal]:
55
+ nodes = self.config.nodes[network]
56
+ round_ndigits = self.config.round_ndigits
57
+ proxies = self.config.proxies
58
+ token_decimals = self.token_decimals[network][token_address] if token_address else -1
59
+ match network:
60
+ case Network.BTC:
61
+ res = btc.get_balance(wallet_address, self.config)
62
+ case Network.ETH:
63
+ if token_address is None:
64
+ res = eth.get_native_balance(nodes, wallet_address, proxies, round_ndigits)
65
+ else:
66
+ res = eth.get_token_balance(nodes, wallet_address, token_address, token_decimals, proxies, round_ndigits)
67
+ case Network.SOL:
68
+ if token_address is None:
69
+ res = solana.get_native_balance(nodes, wallet_address, proxies, round_ndigits)
70
+ else:
71
+ res = solana.get_token_balance(nodes, wallet_address, token_address, token_decimals, proxies, round_ndigits)
71
72
 
72
- def _process_sol(self) -> None:
73
- job = ConcurrentTasks(max_workers=self.config.workers.sol)
74
- for idx, task in enumerate(self.sol):
75
- job.add_task(str(idx), solana.get_balance, args=(task.address, self.config))
76
- job.execute()
77
- for idx, _task in enumerate(self.sol):
78
- self.sol[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
73
+ case _:
74
+ raise ValueError
79
75
 
80
- @staticmethod
81
- def from_config(config: Config) -> Balances:
82
- tasks = Balances(config=config, btc=[], eth=[], sol=[])
83
- for idx, group in enumerate(config.groups):
84
- task_list = [Balances.Balance(group_index=idx, address=a, token_address=group.token_address) for a in group.addresses]
85
- if group.network == Network.BTC:
86
- tasks.btc.extend(task_list)
87
- elif group.network == Network.ETH:
88
- tasks.eth.extend(task_list)
89
- elif group.network == Network.SOL:
90
- tasks.sol.extend(task_list)
91
- return tasks
76
+ self.progress_bar.update(self.progress_bar_task[network], advance=1)
77
+ return res
78
+
79
+ def get_group_balances(self, group_index: int, network: Network) -> list[Balance]:
80
+ # TODO: can we get network by group_index?
81
+ return [b for b in self.tasks[network] if b.group_index == group_index]
82
+
83
+
84
+ # class Balances2(BaseModel):
85
+ # class Balance(BaseModel):
86
+ # group_index: int
87
+ # address: str
88
+ # token_address: str | None
89
+ # balance: Result[Decimal] | None = None
90
+ #
91
+ # config: Config
92
+ # token_decimals: TokenDecimals
93
+ # # separate balance tasks on networks
94
+ # btc: list[Balance]
95
+ # eth: list[Balance]
96
+ # sol: list[Balance]
97
+ #
98
+ # def network_tasks(self, network: Network) -> list[Balance]:
99
+ # if network == Network.BTC:
100
+ # return self.btc
101
+ # elif network == Network.ETH:
102
+ # return self.eth
103
+ # elif network == Network.SOL:
104
+ # return self.sol
105
+ # else:
106
+ # raise ValueError
107
+ #
108
+ # def get_group_balances(self, group_index: int, network: Network) -> list[Balance]:
109
+ # # TODO: can we get network by group_index?
110
+ # if network == Network.BTC:
111
+ # network_balances = self.btc
112
+ # elif network == Network.ETH:
113
+ # network_balances = self.eth
114
+ # elif network == Network.SOL:
115
+ # network_balances = self.sol
116
+ # else:
117
+ # raise ValueError
118
+ #
119
+ # return [b for b in network_balances if b.group_index == group_index]
120
+ #
121
+ # def process(self) -> None:
122
+ # progress = output.create_progress_bar()
123
+ # task_btc = output.create_progress_task(progress, "btc", len(self.btc))
124
+ # task_eth = output.create_progress_task(progress, "eth", len(self.eth))
125
+ # task_sol = output.create_progress_task(progress, "sol", len(self.sol))
126
+ # with progress:
127
+ # job = ConcurrentTasks()
128
+ # job.add_task("btc", self._process_btc, args=(progress, task_btc))
129
+ # job.add_task("eth", self._process_eth, args=(progress, task_eth))
130
+ # job.add_task("sol", self._process_sol, args=(progress, task_sol))
131
+ # job.execute()
132
+ #
133
+ # def _process_btc(self, progress: Progress, task_id: TaskID) -> None:
134
+ # job = ConcurrentTasks(max_workers=self.config.workers.btc)
135
+ # for idx, task in enumerate(self.btc):
136
+ # job.add_task(str(idx), btc.get_balance, args=(task.address, self.config, progress, task_id))
137
+ # job.execute()
138
+ # for idx, _task in enumerate(self.btc):
139
+ # self.btc[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
140
+ #
141
+ # def _process_eth(self, progress: Progress, task_id: TaskID) -> None:
142
+ # job = ConcurrentTasks(max_workers=self.config.workers.eth)
143
+ # for idx, task in enumerate(self.eth):
144
+ # job.add_task(str(idx), self._get_balance,
145
+ # args=(Network.ETH, task.address, task.token_address, self.config, progress, task_id))
146
+ # job.execute()
147
+ # for idx, _task in enumerate(self.eth):
148
+ # self.eth[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
149
+ #
150
+ # def _process_sol(self, progress: Progress, task_id: TaskID) -> None:
151
+ # job = ConcurrentTasks(max_workers=self.config.workers.sol)
152
+ # for idx, task in enumerate(self.sol):
153
+ # job.add_task(str(idx), solana.get_balance, args=(task.address, self.config, progress, task_id))
154
+ # job.execute()
155
+ # for idx, _task in enumerate(self.sol):
156
+ # self.sol[idx].balance = job.result.get(str(idx)) # type: ignore[assignment]
157
+ #
158
+ # @staticmethod
159
+ # def from_config(config: Config, token_decimals: TokenDecimals) -> Balances:
160
+ # tasks = Balances(config=config, btc=[], eth=[], sol=[], token_decimals=token_decimals)
161
+ # for idx, group in enumerate(config.groups):
162
+ # task_list = [Balances.Balance(group_index=idx, address=a, token_address=group.token_address) for a in group.addresses] # noqa
163
+ # if group.network == Network.BTC:
164
+ # tasks.btc.extend(task_list)
165
+ # elif group.network == Network.ETH:
166
+ # tasks.eth.extend(task_list)
167
+ # elif group.network == Network.SOL:
168
+ # tasks.sol.extend(task_list)
169
+ # return tasks
mm_balance/cli.py CHANGED
@@ -9,6 +9,7 @@ from mm_balance import output
9
9
  from mm_balance.balances import Balances
10
10
  from mm_balance.config import Config
11
11
  from mm_balance.price import Prices, get_prices
12
+ from mm_balance.token_decimals import get_token_decimals
12
13
 
13
14
  app = typer.Typer(no_args_is_help=True, pretty_exceptions_enable=False, add_completion=False)
14
15
 
@@ -31,7 +32,8 @@ def cli(
31
32
  config = Config.read_config(config_path, zip_password=zip_password)
32
33
 
33
34
  prices = get_prices(config) if config.price else Prices()
34
- balances = Balances.from_config(config)
35
+ token_decimals = get_token_decimals(config)
36
+ balances = Balances(config, token_decimals)
35
37
  balances.process()
36
38
 
37
39
  output.print_prices(config, prices)
@@ -3,6 +3,11 @@ groups:
3
3
  addresses:
4
4
  - 2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S # binance
5
5
 
6
+ - coin: usdt
7
+ network: sol
8
+ addresses:
9
+ - 2ojv9BAiHUrvsm9gxDe7fJSzbNZSJcxZvf8dqmWGHG8S # binance
10
+
6
11
  - coin: btc
7
12
  comment: coldwallets
8
13
  addresses: |
mm_balance/config.py CHANGED
@@ -4,10 +4,10 @@ from decimal import Decimal
4
4
  from typing import Any, Self
5
5
 
6
6
  import pydash
7
- from mm_std import BaseConfig, Err, PrintFormat, fatal, hr
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.types import DEFAULT_ETH_NODES, DEFAULT_SOL_NODES, EthTokenAddress, Network
10
+ from mm_balance.types import DEFAULT_ETH_NODES, DEFAULT_SOL_NODES, EthTokenAddress, Network, SolTokenAddress
11
11
 
12
12
 
13
13
  class Config(BaseConfig):
@@ -67,14 +67,6 @@ class Config(BaseConfig):
67
67
  def to_list_validator(cls, v: str | list[str] | None) -> list[str]:
68
68
  return cls.to_list_str_validator(v, unique=True, remove_comments=True, split_line=True)
69
69
 
70
- class Workers(BaseConfig):
71
- btc: int = 5
72
- eth: int = 5
73
- sol: int = 5
74
-
75
- class TokenDecimals(BaseConfig):
76
- eth: dict[str, int] = Field(default_factory=dict)
77
-
78
70
  groups: list[Group]
79
71
  addresses: list[AddressGroup] = Field(default_factory=list)
80
72
 
@@ -85,9 +77,7 @@ class Config(BaseConfig):
85
77
  print_format: PrintFormat = PrintFormat.TABLE
86
78
  price: bool = True
87
79
 
88
- # non configs
89
- workers: Workers = Workers()
90
- token_decimals: TokenDecimals = TokenDecimals()
80
+ workers: dict[Network, int] = {network: 5 for network in Network}
91
81
 
92
82
  def btc_groups(self) -> list[Group]:
93
83
  return [g for g in self.groups if g.network == Network.BTC]
@@ -119,16 +109,6 @@ class Config(BaseConfig):
119
109
  if Network.SOL not in self.nodes:
120
110
  self.nodes[Network.SOL] = DEFAULT_SOL_NODES
121
111
 
122
- # load token decimals
123
- for group in self.groups:
124
- if group.network == Network.ETH and group.token_address is not None:
125
- from mm_balance import eth
126
-
127
- decimals_res = eth.get_token_decimals(group.token_address, self)
128
- if isinstance(decimals_res, Err):
129
- fatal(f"can't get decimals for token {group.coin} / {group.token_address}, error={decimals_res.err}")
130
- self.token_decimals.eth[group.token_address] = decimals_res.ok
131
-
132
112
  return self
133
113
 
134
114
 
@@ -151,6 +131,12 @@ def detect_token_address(coin: str, network: str) -> str | None:
151
131
  if coin.lower() == "usdc":
152
132
  return EthTokenAddress.USDC
153
133
 
134
+ if network == Network.SOL.lower():
135
+ if coin.lower() == "usdt":
136
+ return SolTokenAddress.USDT
137
+ if coin.lower() == "usdc":
138
+ return SolTokenAddress.USDC
139
+
154
140
 
155
141
  def get_proxies(proxies_url: str) -> list[str]:
156
142
  try:
mm_balance/output.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from decimal import Decimal
2
2
 
3
3
  from mm_std import Ok, print_table
4
+ from rich.progress import BarColumn, MofNCompleteColumn, Progress, TaskID, TextColumn
4
5
 
5
6
  from mm_balance.balances import Balances
6
7
  from mm_balance.config import Config
@@ -54,3 +55,15 @@ def print_prices(config: Config, prices: Prices) -> None:
54
55
  def print_total(config: Config, balances: Balances, prices: Prices) -> None:
55
56
  total = Total.calc(balances, prices, config)
56
57
  total.print()
58
+
59
+
60
+ def create_progress_bar() -> Progress:
61
+ return Progress(
62
+ TextColumn("[progress.description]{task.description}"),
63
+ BarColumn(),
64
+ MofNCompleteColumn(),
65
+ )
66
+
67
+
68
+ def create_progress_task(progress: Progress, description: str, total: int) -> TaskID:
69
+ return progress.add_task("[green]" + description, total=total)
mm_balance/price.py CHANGED
@@ -5,6 +5,7 @@ import pydash
5
5
  from mm_std import Err, Ok, Result, fatal, hr
6
6
  from mm_std.random_ import random_str_choice
7
7
 
8
+ from mm_balance import output
8
9
  from mm_balance.config import Config
9
10
  from mm_balance.types import EthTokenAddress, Network
10
11
 
@@ -20,17 +21,25 @@ class Prices(dict[str, Decimal]):
20
21
 
21
22
  def get_prices(config: Config) -> Prices:
22
23
  result = Prices()
23
- for group in config.groups:
24
- if group.coin in result:
25
- continue
26
-
27
- coingecko_id = get_coingecko_id(group)
28
- res = get_asset_price(coingecko_id, config.proxies)
29
- if isinstance(res, Ok):
30
- result[group.coin] = res.ok
31
- else:
32
- fatal(res.err)
33
- # raise ValueError(res.err)
24
+ coins_total = len(pydash.uniq([group.coin for group in config.groups]))
25
+
26
+ progress = output.create_progress_bar()
27
+
28
+ with progress:
29
+ task_id = output.create_progress_task(progress, "prices", total=coins_total)
30
+
31
+ for group in config.groups:
32
+ if group.coin in result:
33
+ continue
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)
40
+ else:
41
+ fatal(res.err)
42
+ # raise ValueError(res.err)
34
43
 
35
44
  return result
36
45
 
File without changes
@@ -2,15 +2,19 @@ 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
5
6
 
6
7
  from mm_balance.config import Config
7
8
 
8
9
 
9
- def get_balance(address: str, config: Config) -> Result[Decimal]:
10
- return (
10
+ def get_balance(address: str, config: Config, progress: Progress | None = None, task_id: TaskID | None = None) -> Result[Decimal]:
11
+ res: Result[Decimal] = (
11
12
  BlockstreamClient(proxies=config.proxies, attempts=3)
12
13
  .get_confirmed_balance(address)
13
14
  .and_then(
14
15
  lambda b: Ok(round(Decimal(b / 100_000_000), config.round_ndigits)),
15
16
  )
16
17
  )
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 ADDED
@@ -0,0 +1,46 @@
1
+ from decimal import Decimal
2
+
3
+ from mm_eth import erc20, rpc
4
+ from mm_std import Ok, Result
5
+
6
+
7
+ 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=5, timeout=10).and_then(
9
+ lambda b: Ok(round(Decimal(b / 10**18), round_ndigits)),
10
+ )
11
+
12
+
13
+ def get_token_balance(
14
+ nodes: list[str], wallet_address: str, token_address: str, decimals: int, proxies: list[str], round_ndigits: int
15
+ ) -> Result[Decimal]:
16
+ return erc20.get_balance(
17
+ nodes,
18
+ token_address,
19
+ wallet_address,
20
+ proxies=proxies,
21
+ attempts=5,
22
+ timeout=10,
23
+ ).and_then(
24
+ lambda b: Ok(round(Decimal(b / 10**decimals), round_ndigits)),
25
+ )
26
+
27
+
28
+ def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
29
+ return erc20.get_decimals(nodes, token_address, timeout=10, proxies=proxies, attempts=5)
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
@@ -0,0 +1,22 @@
1
+ from decimal import Decimal
2
+
3
+ from mm_solana import balance, token
4
+ from mm_std import Ok, Result
5
+
6
+
7
+ def get_native_balance(nodes: list[str], address: str, proxies: list[str], round_ndigits: int) -> Result[Decimal]:
8
+ return balance.get_balance_with_retries(nodes, address, retries=5, timeout=5, proxies=proxies).and_then(
9
+ lambda b: Ok(round(Decimal(b / 1_000_000_000), round_ndigits)),
10
+ )
11
+
12
+
13
+ def get_token_balance(
14
+ nodes: list[str], wallet_address: str, token_address: str, decimals: int, proxies: list[str], round_ndigits: int
15
+ ) -> Result[Decimal]:
16
+ return token.get_balance_with_retries(nodes, wallet_address, token_address, retries=5, timeout=5, proxies=proxies).and_then(
17
+ lambda b: Ok(round(Decimal(b / 10**decimals), round_ndigits))
18
+ )
19
+
20
+
21
+ def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
22
+ return token.get_decimals_with_retries(nodes, token_address, retries=5, timeout=5, proxies=proxies)
@@ -0,0 +1,37 @@
1
+ from mm_std import Err, fatal
2
+
3
+ from mm_balance.config import Config
4
+ from mm_balance.rpc import eth, solana
5
+ from mm_balance.types import Network
6
+
7
+
8
+ class TokenDecimals(dict[Network, dict[str, int]]):
9
+ def __init__(self) -> None:
10
+ super().__init__()
11
+ for network in Network:
12
+ self[network] = {}
13
+
14
+
15
+ def get_token_decimals(config: Config) -> TokenDecimals:
16
+ result = TokenDecimals()
17
+
18
+ for group in config.groups:
19
+ if group.token_address is None or group.token_address in result[group.network]:
20
+ continue
21
+
22
+ nodes = config.nodes[group.network]
23
+ proxies = config.proxies
24
+
25
+ match group.network:
26
+ case Network.ETH:
27
+ decimals_res = eth.get_token_decimals(nodes, group.token_address, proxies)
28
+ case Network.SOL:
29
+ decimals_res = solana.get_token_decimals(nodes, group.token_address, proxies)
30
+ case _:
31
+ raise ValueError(f"unsupported network: {group.network}. Cant get token decimals for {group.token_address}")
32
+
33
+ if isinstance(decimals_res, Err):
34
+ fatal(f"can't get decimals for token {group.coin} / {group.token_address}, error={decimals_res.err}")
35
+ result[group.network][group.token_address] = decimals_res.ok
36
+
37
+ return result
mm_balance/total.py CHANGED
@@ -15,7 +15,6 @@ from mm_balance.types import Coin
15
15
  class Total:
16
16
  coins: dict[str, Decimal]
17
17
  coins_share: dict[str, Decimal]
18
- # usd_share: dict[str, Decimal] # all stablecoins have key 'usd'
19
18
  usd_sum: Decimal # sum of all coins in USD
20
19
  usd_sum_share: Decimal
21
20
 
@@ -29,7 +28,6 @@ class Total:
29
28
  def calc(cls, balances: Balances, prices: Prices, config: Config) -> Self:
30
29
  coins: dict[str, Decimal] = defaultdict(Decimal)
31
30
  coins_share: dict[str, Decimal] = defaultdict(Decimal)
32
- # usd_share: dict[str, Decimal] = defaultdict(Decimal)
33
31
  usd_sum = Decimal(0)
34
32
  usd_sum_share = Decimal(0)
35
33
 
@@ -37,7 +35,6 @@ class Total:
37
35
  stablecoin_sum_share = Decimal(0)
38
36
  for group_index, group in enumerate(config.groups):
39
37
  balance_sum = Decimal(0)
40
- # for address_task in [t for t in tasks.network_tasks(group.network) if t.group_index == group_index]:
41
38
  for address_task in balances.get_group_balances(group_index, group.network):
42
39
  if isinstance(address_task.balance, Ok):
43
40
  balance_sum += address_task.balance.ok
mm_balance/types.py CHANGED
@@ -30,3 +30,9 @@ class Network(str, Enum):
30
30
  class EthTokenAddress(str, Enum):
31
31
  USDT = "0xdac17f958d2ee523a2206206994597c13d831ec7"
32
32
  USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
33
+
34
+
35
+ @unique
36
+ class SolTokenAddress(str, Enum):
37
+ USDT = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
38
+ USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: mm-balance
3
- Version: 0.1.8
3
+ Version: 0.1.10
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.2
7
+ Requires-Dist: mm-solana==0.1.4
8
8
  Requires-Dist: typer>=0.12.5
@@ -0,0 +1,18 @@
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,,
mm_balance/eth.py DELETED
@@ -1,29 +0,0 @@
1
- from decimal import Decimal
2
-
3
- from mm_eth import erc20, rpc
4
- from mm_std import Ok, Result
5
-
6
- from mm_balance.config import Config
7
- from mm_balance.types import Network
8
-
9
-
10
- def get_balance(address: str, token_address: str | None, config: Config) -> Result[Decimal]:
11
- if token_address is not None:
12
- return erc20.get_balance(
13
- config.nodes[Network.ETH],
14
- token_address,
15
- address,
16
- proxies=config.proxies,
17
- attempts=5,
18
- timeout=10,
19
- ).and_then(
20
- lambda b: Ok(round(Decimal(b / 10 ** config.token_decimals.eth[token_address]), config.round_ndigits)),
21
- )
22
- else:
23
- return rpc.eth_get_balance(config.nodes[Network.ETH], address, proxies=config.proxies, attempts=5, timeout=10).and_then(
24
- lambda b: Ok(round(Decimal(b / 10**18), config.round_ndigits)),
25
- )
26
-
27
-
28
- def get_token_decimals(token_address: str, config: Config) -> Result[int]:
29
- return erc20.get_decimals(config.nodes[Network.ETH], token_address, timeout=10, proxies=config.proxies, attempts=5)
mm_balance/solana.py DELETED
@@ -1,13 +0,0 @@
1
- from decimal import Decimal
2
-
3
- from mm_solana.balance import sol_balance
4
- from mm_std import Ok, Result
5
-
6
- from mm_balance.config import Config
7
- from mm_balance.types import Network
8
-
9
-
10
- def get_balance(address: str, config: Config) -> Result[Decimal]:
11
- return sol_balance(address=address, nodes=config.nodes[Network.SOL], proxies=config.proxies, attempts=5, timeout=10).and_then(
12
- lambda b: Ok(round(Decimal(b / 1_000_000_000), config.round_ndigits)),
13
- )
@@ -1,16 +0,0 @@
1
- mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_balance/balances.py,sha256=UGhJBecq-2CfNYdXE2EWjDcKkfPG30MERawOtWq5D5E,3399
3
- mm_balance/btc.py,sha256=h8hjcRk6BM0JwhAnB_V39wzeRO94s_hsOlzG7XpE9nk,445
4
- mm_balance/cli.py,sha256=VpiNJdwels7qWuklpV7kNEYm0lhsN4NJ7yENIsQLdK8,1250
5
- mm_balance/config.py,sha256=VGw8f9oQbu5qUJD5lcMnd6kKtXzyX5-CEqcRNd8mgVo,5914
6
- mm_balance/eth.py,sha256=wFpbqo4wHupTeMc9ybCPUkBBaJWxiWCBYJO3LvvU39s,1066
7
- mm_balance/output.py,sha256=hCLq-hynO0c_MJrKSzOoY0p8yFGDZOb5_mE_pqGaBrc,2144
8
- mm_balance/price.py,sha256=xKwF0bWySfnryDYxsPTd2c8C82mrm1TXxIRzRmu_0MA,2577
9
- mm_balance/solana.py,sha256=tK1JHGo9ioIz-jXZ9pRDbACjQh_3vhgqFx1wZKVot6M,460
10
- mm_balance/total.py,sha256=gdH9BzFgc-akVVrsCJ6NqN6cIS9mkEfp-TTKcn01I0U,4944
11
- mm_balance/types.py,sha256=8TflwL3KJ8HQW31qa8xrh-gyJT232lN1XznuNnIR6zM,662
12
- mm_balance/config/example.yml,sha256=6_S0hBdh7gMyO1ZPTGxmL21bBSzzmXuJHB0eWqKGueU,1225
13
- mm_balance-0.1.8.dist-info/METADATA,sha256=3fUpPe2SujgWG7zghwkJAkXOMDY0g4EYIP7KOChheUs,197
14
- mm_balance-0.1.8.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
15
- mm_balance-0.1.8.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
16
- mm_balance-0.1.8.dist-info/RECORD,,