mm-balance 0.2.3__py3-none-any.whl → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import getpass
2
2
  import importlib.metadata
3
- import pathlib
4
3
  import pkgutil
4
+ from pathlib import Path
5
5
  from typing import Annotated
6
6
 
7
7
  import typer
@@ -9,6 +9,7 @@ from mm_std import PrintFormat, fatal, pretty_print_toml
9
9
 
10
10
  from mm_balance.config import Config
11
11
  from mm_balance.constants import NETWORKS
12
+ from mm_balance.diff import BalancesDict, Diff
12
13
  from mm_balance.output.formats import json_format, table_format
13
14
  from mm_balance.price import Prices, get_prices
14
15
  from mm_balance.result import create_balances_result
@@ -42,12 +43,16 @@ def networks_callback(value: bool) -> None:
42
43
 
43
44
  @app.command()
44
45
  def cli(
45
- config_path: Annotated[pathlib.Path, typer.Argument()],
46
+ config_path: Annotated[Path, typer.Argument()],
46
47
  print_format: Annotated[PrintFormat | None, typer.Option("--format", "-f", help="Print format.")] = None,
47
48
  skip_empty: Annotated[bool | None, typer.Option("--skip-empty", "-s", help="Skip empty balances.")] = None,
48
49
  debug: Annotated[bool | None, typer.Option("--debug", "-d", help="Print debug info.")] = None,
49
50
  print_config: Annotated[bool | None, typer.Option("--config", "-c", help="Print config and exit.")] = None,
50
51
  price: Annotated[bool | None, typer.Option("--price/--no-price", help="Print prices.")] = None,
52
+ save_balances_file: Annotated[Path | None, typer.Option("--save-balances-file", help="Save balances file.")] = None,
53
+ diff_from_balances_file: Annotated[
54
+ Path | None, typer.Option("--diff-from-balances-file", help="Diff from balances file.")
55
+ ] = None,
51
56
  _example: Annotated[bool | None, typer.Option("--example", callback=example_callback, help="Print a config example.")] = None,
52
57
  _networks: Annotated[
53
58
  bool | None, typer.Option("--networks", callback=networks_callback, help="Print supported networks.")
@@ -93,6 +98,15 @@ def cli(
93
98
  else:
94
99
  fatal("Unsupported print format")
95
100
 
101
+ if save_balances_file:
102
+ BalancesDict.from_balances_result(result).save_to_path(save_balances_file)
103
+
104
+ if diff_from_balances_file:
105
+ old_balances = BalancesDict.from_file(diff_from_balances_file)
106
+ new_balances = BalancesDict.from_balances_result(result)
107
+ diff = Diff.calc(old_balances, new_balances)
108
+ diff.print(config.settings.print_format)
109
+
96
110
 
97
111
  if __name__ == "__main__":
98
112
  app()
@@ -47,8 +47,8 @@ addresses = "group: binance_eth"
47
47
  ticker = "USDC"
48
48
  network = "aptos"
49
49
  comment = "swap.thala.apt"
50
- token_address = "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC"
51
- token_decimals = 6
50
+ token = "0xf22bede237a07e121b56d91a491eb7bcdfd1f5907926a9e58338f964a01b17fa::asset::USDC"
51
+ decimals = 6
52
52
  addresses = "0x48271d39d0b05bd6efca2278f22277d6fcc375504f9839fd73f74ace240861af"
53
53
 
54
54
 
mm_balance/config.py CHANGED
@@ -20,8 +20,8 @@ class Group(BaseConfig):
20
20
  comment: str = ""
21
21
  ticker: Annotated[str, StringConstraints(to_upper=True)]
22
22
  network: Network
23
- token_address: str | None = None # If None, it's a native token, for example ETH
24
- token_decimals: int | None = None
23
+ token: str | None = None # Token address. If None, it's a native token, for example ETH
24
+ decimals: int | None = None
25
25
  coingecko_id: str | None = None
26
26
  addresses: Annotated[list[str], BeforeValidator(Validators.addresses(unique=True))]
27
27
  share: Decimal = Decimal(1)
@@ -36,10 +36,10 @@ class Group(BaseConfig):
36
36
 
37
37
  @model_validator(mode="after")
38
38
  def final_validator(self) -> Self:
39
- if self.token_address is None:
40
- self.token_address = detect_token_address(self.ticker, self.network)
41
- if self.token_address is not None and self.network.is_evm_network():
42
- self.token_address = self.token_address.lower()
39
+ if self.token is None:
40
+ self.token = detect_token_address(self.ticker, self.network)
41
+ if self.token is not None and self.network.is_evm_network():
42
+ self.token = self.token.lower()
43
43
  return self
44
44
 
45
45
  def process_addresses(self, address_groups: list[AddressGroup]) -> None:
mm_balance/diff.py ADDED
@@ -0,0 +1,168 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from decimal import Decimal
6
+ from pathlib import Path
7
+
8
+ from deepdiff.diff import DeepDiff
9
+ from mm_std import PrintFormat, print_json, print_plain, print_table
10
+ from pydantic import BaseModel, RootModel
11
+
12
+ from mm_balance.result import Balance, BalancesResult
13
+
14
+
15
+ class BalancesDict(RootModel[dict[str, dict[str, dict[str, Decimal]]]]): # network->ticker->address->balance
16
+ def networks(self) -> set[str]:
17
+ return set(self.model_dump().keys())
18
+
19
+ def tickers(self, network: str) -> set[str]:
20
+ return set(self.model_dump()[network].keys())
21
+
22
+ def save_to_path(self, balances_file: Path) -> None:
23
+ json.dump(self.model_dump(), balances_file.open("w"), default=str, indent=2)
24
+
25
+ @staticmethod
26
+ def from_balances_result(result: BalancesResult) -> BalancesDict:
27
+ data: dict[str, dict[str, dict[str, Decimal]]] = {} # network->ticker->address->balance
28
+ for group in result.groups:
29
+ if group.network not in data:
30
+ data[group.network] = {}
31
+ if group.ticker not in data[group.network]:
32
+ data[group.network][group.ticker] = {}
33
+ for address in group.addresses:
34
+ if isinstance(address.balance, Balance):
35
+ data[group.network][group.ticker][address.address] = address.balance.balance
36
+ return BalancesDict(data)
37
+
38
+ @staticmethod
39
+ def from_file(path: Path) -> BalancesDict:
40
+ return BalancesDict(json.load(path.open("r")))
41
+
42
+
43
+ class Diff(BaseModel):
44
+ network_added: list[str]
45
+ network_removed: list[str]
46
+
47
+ ticker_added: dict[str, list[str]] # network -> tickers
48
+ ticker_removed: dict[str, list[str]] # network -> tickers
49
+
50
+ address_added: dict[str, dict[str, list[str]]] # network -> ticker -> addresses
51
+ address_removed: dict[str, dict[str, list[str]]] # network -> ticker -> addresses
52
+
53
+ balance_changed: dict[str, dict[str, dict[str, tuple[Decimal, Decimal]]]] # network->ticker->address->(old_value,new_value)
54
+
55
+ def print(self, print_format: PrintFormat) -> None:
56
+ match print_format:
57
+ case PrintFormat.TABLE:
58
+ self._print_table()
59
+ case PrintFormat.JSON:
60
+ self._print_json()
61
+ case _:
62
+ raise ValueError(f"Unsupported print format: {print_format}")
63
+
64
+ def _print_table(self) -> None:
65
+ if (
66
+ not self.network_added
67
+ and not self.network_removed
68
+ and not self.ticker_added
69
+ and not self.ticker_removed
70
+ and not self.address_added
71
+ and not self.address_removed
72
+ and not self.balance_changed
73
+ ):
74
+ print_plain("Diff: no changes")
75
+ return
76
+
77
+ print_plain("\nDiff")
78
+
79
+ if self.network_added:
80
+ print_plain(f"networks added: {self.network_added}")
81
+ if self.network_removed:
82
+ print_plain(f"networks removed: {self.network_removed}")
83
+ if self.ticker_added:
84
+ print_plain(f"tickers added: {self.ticker_added}")
85
+ if self.ticker_removed:
86
+ print_plain(f"tickers removed: {self.ticker_removed}")
87
+ if self.address_added:
88
+ print_plain(f"addresses added: {self.address_added}")
89
+ if self.address_removed:
90
+ print_plain(f"addresses removed: {self.address_removed}")
91
+
92
+ if self.balance_changed:
93
+ rows = []
94
+ for network in self.balance_changed:
95
+ for ticker in self.balance_changed[network]:
96
+ for address in self.balance_changed[network][ticker]:
97
+ old_value, new_value = self.balance_changed[network][ticker][address]
98
+ rows.append([network, ticker, address, old_value, new_value, new_value - old_value])
99
+ print_table("", ["Network", "Ticker", "Address", "Old", "New", "Change"], rows)
100
+
101
+ def _print_json(self) -> None:
102
+ print_json(data=self.model_dump(), default_serializer=str)
103
+
104
+ @staticmethod
105
+ def calc(balances1: BalancesDict, balances2: BalancesDict) -> Diff:
106
+ dd = DeepDiff(balances1.model_dump(), balances2.model_dump(), ignore_order=True)
107
+ # Initialize empty collections for Diff fields.
108
+
109
+ network_added = []
110
+ network_removed = []
111
+ ticker_added: dict[str, list[str]] = {}
112
+ ticker_removed: dict[str, list[str]] = {}
113
+ address_added: dict[str, dict[str, list[str]]] = {}
114
+ address_removed: dict[str, dict[str, list[str]]] = {}
115
+ balance_changed: dict[str, dict[str, dict[str, tuple[Decimal, Decimal]]]] = {}
116
+
117
+ # Helper to extract keys from DeepDiff paths.
118
+ def extract_keys(path: str) -> list[str]:
119
+ # DeepDiff paths look like "root['network']['ticker']['address']"
120
+ return re.findall(r"\['([^']+)'\]", path)
121
+
122
+ # Process dictionary_item_added
123
+ for path in dd.get("dictionary_item_added", []):
124
+ keys = extract_keys(path)
125
+ if len(keys) == 1:
126
+ # New network added.
127
+ network_added.append(keys[0])
128
+ elif len(keys) == 2:
129
+ # New ticker added under an existing network.
130
+ network, ticker = keys
131
+ ticker_added.setdefault(network, []).append(ticker)
132
+ elif len(keys) == 3:
133
+ # New address added under an existing network and ticker.
134
+ network, ticker, address = keys
135
+ address_added.setdefault(network, {}).setdefault(ticker, []).append(address)
136
+
137
+ # Process dictionary_item_removed
138
+ for path in dd.get("dictionary_item_removed", []):
139
+ keys = extract_keys(path)
140
+ if len(keys) == 1:
141
+ network_removed.append(keys[0])
142
+ elif len(keys) == 2:
143
+ network, ticker = keys
144
+ ticker_removed.setdefault(network, []).append(ticker)
145
+ elif len(keys) == 3:
146
+ network, ticker, address = keys
147
+ address_removed.setdefault(network, {}).setdefault(ticker, []).append(address)
148
+
149
+ # Process values_changed for balance differences.
150
+ for path, change in dd.get("values_changed", {}).items():
151
+ keys = extract_keys(path)
152
+ if len(keys) != 3:
153
+ continue
154
+ network, ticker, address = keys
155
+ balance_changed.setdefault(network, {}).setdefault(ticker, {})[address] = (
156
+ Decimal(change["old_value"]),
157
+ Decimal(change["new_value"]),
158
+ )
159
+
160
+ return Diff(
161
+ network_added=sorted(network_added),
162
+ network_removed=sorted(network_removed),
163
+ ticker_added={k: sorted(v) for k, v in ticker_added.items()},
164
+ ticker_removed={k: sorted(v) for k, v in ticker_removed.items()},
165
+ address_added={k: {tk: sorted(vv) for tk, vv in v.items()} for k, v in address_added.items()},
166
+ address_removed={k: {tk: sorted(vv) for tk, vv in v.items()} for k, v in address_removed.items()},
167
+ balance_changed=balance_changed,
168
+ )
@@ -33,7 +33,7 @@ def print_prices(config: Config, prices: Prices) -> None:
33
33
  rows = []
34
34
  for ticker, price in prices.items():
35
35
  rows.append(
36
- [ticker, format_number(round(price, config.settings.round_ndigits), config.settings.format_number_separator, "$")]
36
+ [ticker, format_number(price, config.settings.format_number_separator, "$", config.settings.round_ndigits)]
37
37
  )
38
38
  print_table("Prices", ["coin", "usd"], rows)
39
39
 
@@ -3,7 +3,9 @@ from decimal import Decimal
3
3
  from rich.progress import BarColumn, MofNCompleteColumn, Progress, TaskID, TextColumn
4
4
 
5
5
 
6
- def format_number(value: Decimal, separator: str, extra: str | None = None) -> str:
6
+ def format_number(value: Decimal, separator: str, extra: str | None = None, round_ndigits: int | None = None) -> str:
7
+ if round_ndigits is not None and value > 0:
8
+ value = round(value, round_ndigits)
7
9
  str_value = f"{value:,}".replace(",", separator)
8
10
  if extra == "$":
9
11
  return "$" + str_value
mm_balance/result.py CHANGED
@@ -7,6 +7,7 @@ from mm_std import Ok
7
7
  from mm_balance.config import Config, Group
8
8
  from mm_balance.constants import USD_STABLECOINS, Network
9
9
  from mm_balance.price import Prices
10
+ from mm_balance.utils import round_decimal
10
11
  from mm_balance.workers import Task, Workers
11
12
 
12
13
 
@@ -62,6 +63,19 @@ def create_balances_result(config: Config, prices: Prices, workers: Workers) ->
62
63
  return BalancesResult(groups=groups, total=total, total_share=total_share)
63
64
 
64
65
 
66
+ # def save_balances_file(result: BalancesResult, balances_file: Path) -> None:
67
+ # data = {}
68
+ # for group in result.groups:
69
+ # if group.network not in data:
70
+ # data[group.network] = {}
71
+ # if group.ticker not in data[group.network]:
72
+ # data[group.network][group.ticker] = {}
73
+ # for address in group.addresses:
74
+ # if isinstance(address.balance, Balance):
75
+ # data[group.network][group.ticker][address.address] = float(address.balance.balance)
76
+ # json.dump(data, balances_file.open("w"), indent=2)
77
+
78
+
65
79
  def _create_total(use_share: bool, groups: list[GroupResult]) -> Total:
66
80
  coin_balances: dict[str, Decimal] = defaultdict(Decimal) # ticker -> balance
67
81
  coin_usd_values: dict[str, Decimal] = defaultdict(Decimal) # ticker -> usd value
@@ -106,7 +120,7 @@ def _create_group_result(config: Config, group: Group, tasks: list[Task], prices
106
120
  coin_value = task.balance.ok
107
121
  usd_value = Decimal(0)
108
122
  if group.ticker in prices:
109
- usd_value = round(coin_value * prices[group.ticker], config.settings.round_ndigits)
123
+ usd_value = round_decimal(coin_value * prices[group.ticker], config.settings.round_ndigits)
110
124
  balance = Balance(balance=coin_value, usd_value=usd_value)
111
125
  balance_sum += balance.balance
112
126
  usd_sum += balance.usd_value
mm_balance/rpc/btc.py CHANGED
@@ -4,11 +4,12 @@ from mm_btc.blockstream import BlockstreamClient
4
4
  from mm_std import Ok, Result
5
5
 
6
6
  from mm_balance.constants import RETRIES_BALANCE
7
+ from mm_balance.utils import scale_and_round
7
8
 
8
9
 
9
10
  def get_balance(address: str, proxies: list[str], round_ndigits: int) -> Result[Decimal]:
10
11
  return (
11
12
  BlockstreamClient(proxies=proxies, attempts=RETRIES_BALANCE)
12
13
  .get_confirmed_balance(address)
13
- .and_then(lambda b: Ok(round(Decimal(b / 100_000_000), round_ndigits)))
14
+ .and_then(lambda b: Ok(scale_and_round(b, 8, round_ndigits)))
14
15
  )
mm_balance/rpc/evm.py CHANGED
@@ -4,6 +4,7 @@ from mm_eth import erc20, rpc
4
4
  from mm_std import Ok, Result
5
5
 
6
6
  from mm_balance.constants import RETRIES_BALANCE, RETRIES_DECIMALS, TIMEOUT_BALANCE, TIMEOUT_DECIMALS
7
+ from mm_balance.utils import scale_and_round
7
8
 
8
9
 
9
10
  def get_balance(
@@ -20,7 +21,7 @@ def get_balance(
20
21
  )
21
22
  else:
22
23
  res = rpc.eth_get_balance(nodes, wallet, proxies=proxies, attempts=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE)
23
- return res.and_then(lambda b: Ok(round(Decimal(b / 10**decimals), round_ndigits)))
24
+ return res.and_then(lambda b: Ok(scale_and_round(b, decimals, round_ndigits)))
24
25
 
25
26
 
26
27
  def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
mm_balance/rpc/solana.py CHANGED
@@ -4,6 +4,7 @@ from mm_sol import balance, token
4
4
  from mm_std import Ok, Result
5
5
 
6
6
  from mm_balance.constants import RETRIES_BALANCE, RETRIES_DECIMALS, TIMEOUT_BALANCE, TIMEOUT_DECIMALS
7
+ from mm_balance.utils import scale_and_round
7
8
 
8
9
 
9
10
  def get_balance(
@@ -17,8 +18,7 @@ def get_balance(
17
18
  res = balance.get_token_balance_with_retries(
18
19
  nodes, wallet, token, retries=RETRIES_BALANCE, timeout=TIMEOUT_BALANCE, proxies=proxies
19
20
  )
20
-
21
- return res.and_then(lambda b: Ok(round(Decimal(b / 10**decimals), round_ndigits)))
21
+ return res.and_then(lambda b: Ok(scale_and_round(b, decimals, round_ndigits)))
22
22
 
23
23
 
24
24
  def get_token_decimals(nodes: list[str], token_address: str, proxies: list[str]) -> Result[int]:
@@ -18,12 +18,12 @@ def get_token_decimals(config: Config) -> TokenDecimals:
18
18
 
19
19
  for group in config.groups:
20
20
  # token_decimals is already known
21
- if group.token_decimals is not None:
22
- result[group.network][group.token_address] = group.token_decimals
21
+ if group.decimals is not None:
22
+ result[group.network][group.token] = group.decimals
23
23
  continue
24
24
 
25
25
  # get token_decimals for known native tokens
26
- if group.token_address is None:
26
+ if group.token is None:
27
27
  if group.network.is_evm_network():
28
28
  result[group.network][None] = 18
29
29
  elif group.network == NETWORK_SOLANA:
@@ -36,18 +36,18 @@ def get_token_decimals(config: Config) -> TokenDecimals:
36
36
 
37
37
  # get token_decimals via RPC
38
38
  # TODO: group.token_address must be in normalized form, otherwise it can be different for the same token
39
- if group.token_address in result[group.network]:
39
+ if group.token in result[group.network]:
40
40
  continue # don't request for a token_decimals twice
41
41
 
42
42
  nodes = config.nodes[group.network]
43
43
  if group.network.is_evm_network():
44
- res = evm.get_token_decimals(nodes, group.token_address, proxies)
44
+ res = evm.get_token_decimals(nodes, group.token, proxies)
45
45
  elif group.network == NETWORK_SOLANA:
46
- res = solana.get_token_decimals(nodes, group.token_address, proxies)
46
+ res = solana.get_token_decimals(nodes, group.token, proxies)
47
47
  else:
48
- fatal(f"unsupported network: {group.network}. Cant get token decimals for {group.token_address}")
48
+ fatal(f"unsupported network: {group.network}. Cant get token decimals for {group.token}")
49
49
  if isinstance(res, Err):
50
- fatal(f"can't get decimals for token {group.ticker} / {group.token_address}, error={res.err}")
51
- result[group.network][group.token_address] = res.ok
50
+ fatal(f"can't get decimals for token {group.ticker} / {group.token}, error={res.err}")
51
+ result[group.network][group.token] = res.ok
52
52
 
53
53
  return result
mm_balance/utils.py CHANGED
@@ -8,3 +8,15 @@ def fnumber(value: Decimal, separator: str, extra: str | None = None) -> str:
8
8
  if extra == "%":
9
9
  return str_value + "%"
10
10
  return str_value
11
+
12
+
13
+ def scale_and_round(value: int, decimals: int, round_ndigits: int) -> Decimal:
14
+ if value == 0:
15
+ return Decimal(0)
16
+ return round(Decimal(value / 10**decimals), round_ndigits)
17
+
18
+
19
+ def round_decimal(value: Decimal, round_ndigits: int) -> Decimal:
20
+ if value == Decimal(0):
21
+ return Decimal(0)
22
+ return round(value, round_ndigits)
mm_balance/workers.py CHANGED
@@ -28,7 +28,7 @@ class Workers:
28
28
  self.progress_bar_task: dict[Network, TaskID] = {}
29
29
 
30
30
  for idx, group in enumerate(config.groups):
31
- task_list = [Task(group_index=idx, wallet_address=a, token_address=group.token_address) for a in group.addresses]
31
+ task_list = [Task(group_index=idx, wallet_address=a, token_address=group.token) for a in group.addresses]
32
32
  self.tasks[group.network].extend(task_list)
33
33
 
34
34
  for network in config.networks():
@@ -1,9 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mm-balance
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Requires-Python: >=3.12
5
+ Requires-Dist: deepdiff==8.2.0
5
6
  Requires-Dist: mm-aptos==0.2.0
6
7
  Requires-Dist: mm-btc==0.3.0
7
- Requires-Dist: mm-eth==0.5.2
8
+ Requires-Dist: mm-eth==0.5.3
8
9
  Requires-Dist: mm-sol==0.5.1
9
- Requires-Dist: typer>=0.15.1
10
+ Requires-Dist: typer==0.15.1
@@ -0,0 +1,25 @@
1
+ mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ mm_balance/cli.py,sha256=nRDVejN-dnr1iRezBxNk4z0oLa59tiwzIVhgeOGzvbo,4498
3
+ mm_balance/config.py,sha256=gywHNWEQL1xeG778cuca5aBoXElLIfoGle3xxW6m_0U,4564
4
+ mm_balance/constants.py,sha256=kqG2zuwv0l-PzDHIrMJVQpfQWiXjr2DsqGPcKmqNJLo,2334
5
+ mm_balance/diff.py,sha256=GPRbykty2TIBBM8jpYXOV9Itjyd_mz0BTUsQ8KX7cNo,7099
6
+ mm_balance/price.py,sha256=DzvcQngS6wgi_4YWoXxGvOuOkwJvUbN0KI8DeIxbB5A,1494
7
+ mm_balance/result.py,sha256=-Ebq07JMLcQAmRs82cA6aYMbsT1qbZSyAOixr9K_wbg,5157
8
+ mm_balance/token_decimals.py,sha256=N3YppB2F3J_OuNkawpAHLVD-4MRCoVjBI01_OoRg5sY,2201
9
+ mm_balance/utils.py,sha256=_UMX3TV350Sr222tAnxGUf0R5McpwloNTQC-U-xiuHc,636
10
+ mm_balance/workers.py,sha256=eg0Ve1xVu3Kd_thfVmPsp6tEdJsYYvs1ipXiu5rKItY,3758
11
+ mm_balance/config/example.toml,sha256=f3Jr40ziOCv_Txf-BysS89c9r7uS-IYHuvwbQ-iftUs,1802
12
+ mm_balance/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ mm_balance/output/utils.py,sha256=zyN9igdaXGY_vKfc-3dJ13mH1T7JDke3AeB4MY_3AsA,842
14
+ mm_balance/output/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ mm_balance/output/formats/json_format.py,sha256=japDhWBVaZ9Znwrhi6BLsUEyn2zyNVxPFYhH7SiILb8,893
16
+ mm_balance/output/formats/table_format.py,sha256=QtWq6ETIccfBTw-9SPypeZrX2zfZwpoCFi_Qe_qOLAA,4751
17
+ mm_balance/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ mm_balance/rpc/aptos.py,sha256=1JCYCqDim4tk1axXscaAJRXPd4J6vV1ABFbwMbPgrL0,641
19
+ mm_balance/rpc/btc.py,sha256=wBMxUjbqdQipVsTFVkj4tk7loErA2czLVfvG8vjFLeE,493
20
+ mm_balance/rpc/evm.py,sha256=LaU2csGL-VlQauCiTX_WFnstvTyZLMP5gDw2LyV53m8,1048
21
+ mm_balance/rpc/solana.py,sha256=10rJ4eEr9sfEfhXx-X2R7bdJ5dL7bVMwHHfJ4R3QR7U,1071
22
+ mm_balance-0.3.0.dist-info/METADATA,sha256=Owy1HtXoCk7RhiqeEwijv80KKLuDBHbgQdHOrjAxvEs,256
23
+ mm_balance-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
24
+ mm_balance-0.3.0.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
25
+ mm_balance-0.3.0.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- mm_balance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_balance/cli.py,sha256=AHaD6w97H8ru8nnQv2dcqh9v-d9BVirnlsClbLyHf6M,3796
3
- mm_balance/config.py,sha256=3qEg9xGCoH6WX91dlmjXVVhkCjJf8KFOmfqE8NgSc64,4603
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=15Bjk_zkbhx9CqFgx1kbb2cRSBY9-kPKrej7N_8ulTk,1816
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.3.dist-info/METADATA,sha256=5FAngHypNiHnXLneqRH9E3n1jX45TIdJekZ4uAIKs4M,225
22
- mm_balance-0.2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- mm_balance-0.2.3.dist-info/entry_points.txt,sha256=rSnP0ZW1a3ACNwTWM7T53CmOycKbzhG43m2_wseENng,50
24
- mm_balance-0.2.3.dist-info/RECORD,,