twbal.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env python3
  2. #
  3. # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
  4. # Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. """
  19. twbal: Tracking wallet getbalance class for the MMGen suite
  20. """
  21. from .color import red,green
  22. from .util import altcoin_subclass
  23. from .base_obj import AsyncInit
  24. from .objmethods import MMGenObject
  25. from .rpc import rpc_init
  26. from .tw import get_tw_label
  27. class TwGetBalance(MMGenObject,metaclass=AsyncInit):
  28. fs = '{w:13} {u:<16} {p:<16} {c}'
  29. def __new__(cls,proto,*args,**kwargs):
  30. return MMGenObject.__new__(altcoin_subclass(cls,proto,'twbal'))
  31. async def __init__(self,proto,minconf,quiet):
  32. self.minconf = minconf
  33. self.quiet = quiet
  34. self.data = {k:[proto.coin_amt('0')] * 4 for k in ('TOTAL','Non-MMGen','Non-wallet')}
  35. self.rpc = await rpc_init(proto)
  36. self.proto = proto
  37. await self.create_data()
  38. async def create_data(self):
  39. # 0: unconfirmed, 1: below minconf, 2: confirmed, 3: spendable (privkey in wallet)
  40. lbl_id = ('account','label')['label_api' in self.rpc.caps]
  41. for d in await self.rpc.call('listunspent',0):
  42. lbl = get_tw_label(self.proto,d[lbl_id])
  43. if lbl:
  44. if lbl.mmid.type == 'mmgen':
  45. key = lbl.mmid.obj.sid
  46. if key not in self.data:
  47. self.data[key] = [self.proto.coin_amt('0')] * 4
  48. else:
  49. key = 'Non-MMGen'
  50. else:
  51. lbl,key = None,'Non-wallet'
  52. amt = self.proto.coin_amt(d['amount'])
  53. if not d['confirmations']:
  54. self.data['TOTAL'][0] += amt
  55. self.data[key][0] += amt
  56. conf_level = (1,2)[d['confirmations'] >= self.minconf]
  57. self.data['TOTAL'][conf_level] += amt
  58. self.data[key][conf_level] += amt
  59. if d['spendable']:
  60. self.data[key][3] += amt
  61. def format(self):
  62. def gen_output():
  63. if self.proto.chain_name != 'mainnet':
  64. yield 'Chain: ' + green(self.proto.chain_name.upper())
  65. if self.quiet:
  66. yield str(self.data['TOTAL'][2] if self.data else 0)
  67. else:
  68. yield self.fs.format(
  69. w = 'Wallet',
  70. u = ' Unconfirmed',
  71. p = f' <{self.minconf} confirms',
  72. c = f' >={self.minconf} confirms' )
  73. for key in sorted(self.data):
  74. if not any(self.data[key]):
  75. continue
  76. yield self.fs.format(**dict(zip(
  77. ('w','u','p','c'),
  78. [key+':'] + [a.fmt(color=True,suf=' '+self.proto.dcoin) for a in self.data[key]]
  79. )))
  80. for key,vals in list(self.data.items()):
  81. if key == 'TOTAL':
  82. continue
  83. if vals[3]:
  84. yield red(f'Warning: this wallet contains PRIVATE KEYS for {key} outputs!')
  85. return '\n'.join(gen_output()).rstrip()