rpc.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. tool/rpc.py: JSON/RPC routines for the 'mmgen-tool' utility
  20. """
  21. from .common import tool_cmd_base,options_annot_str
  22. from ..tw.common import TwCommon
  23. class tool_cmd(tool_cmd_base):
  24. "tracking wallet commands using the JSON-RPC interface"
  25. need_proto = True
  26. need_amt = True
  27. async def daemon_version(self):
  28. "print coin daemon version"
  29. from ..rpc import rpc_init
  30. r = await rpc_init( self.proto, ignore_daemon_version=True )
  31. return f'{r.daemon.coind_name} version {r.daemon_version} ({r.daemon_version_str})'
  32. async def getbalance(self,minconf=1,quiet=False,pager=False):
  33. "list confirmed/unconfirmed, spendable/unspendable balances in tracking wallet"
  34. from ..tw.bal import TwGetBalance
  35. return (await TwGetBalance(self.proto,minconf,quiet)).format()
  36. async def listaddress(self,
  37. mmgen_addr:str,
  38. minconf = 1,
  39. pager = False,
  40. showempty = True,
  41. showbtcaddr = True,
  42. age_fmt: options_annot_str(TwCommon.age_fmts) = 'confs' ):
  43. "list the specified MMGen address and its balance"
  44. return await self.listaddresses(
  45. mmgen_addrs = mmgen_addr,
  46. minconf = minconf,
  47. pager = pager,
  48. showempty = showempty,
  49. showbtcaddrs = showbtcaddr,
  50. age_fmt = age_fmt )
  51. async def listaddresses(self,
  52. mmgen_addrs:'(range or list)' = '',
  53. minconf = 1,
  54. showempty = False,
  55. pager = False,
  56. showbtcaddrs = True,
  57. all_labels = False,
  58. sort: options_annot_str(['reverse','age']) = '',
  59. age_fmt: options_annot_str(TwCommon.age_fmts) = 'confs' ):
  60. "list MMGen addresses and their balances"
  61. show_age = bool(age_fmt)
  62. if sort:
  63. sort = set(sort.split(','))
  64. sort_params = {'reverse','age'}
  65. if not sort.issubset( sort_params ):
  66. from ..util import die
  67. die(1,"The sort option takes the following parameters: '{}'".format( "','".join(sort_params) ))
  68. usr_addr_list = []
  69. if mmgen_addrs:
  70. a = mmgen_addrs.rsplit(':',1)
  71. if len(a) != 2:
  72. from ..util import die
  73. die(1,
  74. f'{mmgen_addrs}: invalid address list argument ' +
  75. '(must be in form <seed ID>:[<type>:]<idx list>)' )
  76. from ..addr import MMGenID
  77. from ..addrlist import AddrIdxList
  78. usr_addr_list = [MMGenID(self.proto,f'{a[0]}:{i}') for i in AddrIdxList(a[1])]
  79. from ..tw.addrs import TwAddrList
  80. al = await TwAddrList( self.proto, usr_addr_list, minconf, showempty, showbtcaddrs, all_labels )
  81. if not al:
  82. from ..util import die
  83. die(0,('No tracked addresses with balances!','No tracked addresses!')[showempty])
  84. return await al.format( showbtcaddrs, sort, show_age, age_fmt or 'confs' )
  85. async def twops(self,
  86. obj,pager,reverse,wide,sort,age_fmt,show_mmid,wide_show_confs,interactive):
  87. obj.reverse = reverse
  88. obj.age_fmt = age_fmt
  89. obj.show_mmid = show_mmid
  90. await obj.get_data(sort_key=sort,reverse_sort=reverse)
  91. if interactive:
  92. await obj.view_and_sort()
  93. return True
  94. elif wide:
  95. return await obj.format_for_printing( color=True, show_confs=wide_show_confs )
  96. else:
  97. return await obj.format_for_display()
  98. async def twview(self,
  99. pager = False,
  100. reverse = False,
  101. wide = False,
  102. minconf = 1,
  103. sort = 'age',
  104. age_fmt: options_annot_str(TwCommon.age_fmts) = 'confs',
  105. show_mmid = True,
  106. wide_show_confs = True,
  107. interactive = False ):
  108. "view tracking wallet unspent outputs"
  109. from ..tw.unspent import TwUnspentOutputs
  110. obj = await TwUnspentOutputs(self.proto,minconf=minconf)
  111. ret = await self.twops(
  112. obj,pager,reverse,wide,sort,age_fmt,show_mmid,wide_show_confs,interactive)
  113. del obj.wallet
  114. return ret
  115. async def add_label(self,mmgen_or_coin_addr:str,label:str):
  116. "add descriptive label for address in tracking wallet"
  117. from ..tw.ctl import TrackingWallet
  118. await (await TrackingWallet(self.proto,mode='w')).add_label( mmgen_or_coin_addr, label, on_fail='raise' )
  119. return True
  120. async def remove_label(self,mmgen_or_coin_addr:str):
  121. "remove descriptive label for address in tracking wallet"
  122. await self.add_label( mmgen_or_coin_addr, '' )
  123. return True
  124. async def remove_address(self,mmgen_or_coin_addr:str):
  125. "remove an address from tracking wallet"
  126. from ..tw.ctl import TrackingWallet
  127. ret = await (await TrackingWallet(self.proto,mode='w')).remove_address(mmgen_or_coin_addr) # returns None on failure
  128. if ret:
  129. from ..util import msg
  130. msg(f'Address {ret!r} deleted from tracking wallet')
  131. return ret