json.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #!/usr/bin/env python3
  2. #
  3. # MMGen Wallet, a terminal-based cryptocurrency wallet
  4. # Copyright (C)2013-2025 The MMGen Project <mmgen@tuta.io>
  5. # Licensed under the GNU General Public License, Version 3:
  6. # https://www.gnu.org/licenses
  7. # Public project repositories:
  8. # https://github.com/mmgen/mmgen-wallet
  9. # https://gitlab.com/mmgen/mmgen-wallet
  10. """
  11. proto.eth.tw.json: export and import tracking wallet to JSON format
  12. """
  13. from collections import namedtuple
  14. from ....tw.json import TwJSON
  15. from ....tw.shared import TwMMGenID
  16. class EthereumTwJSON(TwJSON):
  17. class Base(TwJSON.Base):
  18. def __init__(self, proto, *args, **kwargs):
  19. self.params_keys = ['symbol', 'decimals']
  20. self.params_tuple = namedtuple('params_tuple', self.params_keys)
  21. super().__init__(proto, *args, **kwargs)
  22. @property
  23. def mappings_json(self):
  24. def gen_mappings(data):
  25. for d in data:
  26. yield (d.mmgen_id, d.address) if hasattr(d, 'mmgen_id') else d
  27. return self.json_dump({
  28. 'accounts': list(gen_mappings(self.entries['accounts'])),
  29. 'tokens': {k: list(gen_mappings(v)) for k, v in self.entries['tokens'].items()}})
  30. @property
  31. def num_entries(self):
  32. return len(self.entries['accounts']) + len(self.entries['tokens'])
  33. class Import(TwJSON.Import, Base):
  34. info_msg = """
  35. This utility will recreate a new tracking wallet from the supplied JSON dump.
  36. If the dump contains address balances, balances will be updated from it.
  37. """
  38. @property
  39. async def tracking_wallet_exists(self):
  40. return bool(self.twctl.data['accounts'] or self.twctl.data['tokens'])
  41. async def create_tracking_wallet(self):
  42. return True
  43. async def get_entries(self):
  44. edata = self.data['data']['entries']
  45. def gen_entries(data):
  46. for d in data:
  47. if len(d) == 2:
  48. yield self.params_tuple(*d)
  49. else:
  50. e = self.entry_tuple_in(*d)
  51. yield self.entry_tuple(
  52. TwMMGenID(self.proto, e.mmgen_id),
  53. e.address,
  54. getattr(e, 'amount', '0'),
  55. e.comment)
  56. def gen_token_entries():
  57. for token_addr, token_data in edata['tokens'].items():
  58. yield (
  59. token_addr,
  60. list(gen_entries(token_data)),
  61. )
  62. return {
  63. 'accounts': list(gen_entries(edata['accounts'])),
  64. 'tokens': dict(list(gen_token_entries()))}
  65. async def do_import(self, batch):
  66. from ....obj import TwComment
  67. def gen_data(data):
  68. for d in data:
  69. if hasattr(d, 'address'):
  70. yield (
  71. d.address,
  72. {'mmid': d.mmgen_id, 'comment': TwComment(d.comment)}
  73. | ({} if d.amount is None else {'balance': d.amount}))
  74. else:
  75. yield ('params', {'symbol': d.symbol, 'decimals': d.decimals})
  76. self.twctl.data = { # keys must be in correct order
  77. 'coin': self.coin.upper(),
  78. 'network': self.network.upper(),
  79. 'accounts': dict(gen_data(self.entries['accounts'])),
  80. 'tokens': {k: dict(gen_data(v)) for k, v in self.entries['tokens'].items()}}
  81. self.twctl.write(quiet=False)
  82. class Export(TwJSON.Export, Base):
  83. async def get_entries(self, *, include_amts=True):
  84. def gen_data(data):
  85. for k, v in data.items():
  86. if k == 'params':
  87. yield self.params_tuple(**v)
  88. elif include_amts:
  89. yield self.entry_tuple(TwMMGenID(self.proto, v['mmid']), k, v.get('balance'), v['comment'])
  90. else:
  91. yield self.entry_tuple_in(TwMMGenID(self.proto, v['mmid']), k, v['comment'])
  92. def gen_token_data():
  93. for token_addr, token_data in self.twctl.data['tokens'].items():
  94. yield (
  95. token_addr,
  96. sorted(
  97. gen_data(token_data),
  98. key = lambda x: x.mmgen_id.sort_key if hasattr(x, 'mmgen_id') else '+'
  99. )
  100. )
  101. return {
  102. 'accounts': sorted(
  103. gen_data(self.twctl.data['accounts']),
  104. key = lambda x: x.mmgen_id.sort_key),
  105. 'tokens': dict(sorted(gen_token_data()))}
  106. @property
  107. async def entries_out(self):
  108. return await self.get_entries(include_amts='amount' in self.keys)
  109. @property
  110. async def total(self):
  111. return sum(self.proto.coin_amt(i.amount) for i in self.entries['accounts']) or self.proto.coin_amt('0')