XMR compat: address/account creation
Example:
# Press ‘N’ or ‘n’ at the prompt to create new account or address:
$ mmgen-tool --coin=xmr listaddresses interactive=1
Testing/demo:
$ test/cmdtest.py --coin=xmr -e xmr_compat
This commit is contained in:
parent
a75518e78f
commit
7b53f4337f
5 changed files with 134 additions and 10 deletions
|
|
@ -1 +1 @@
|
|||
16.1.dev24
|
||||
16.1.dev25
|
||||
|
|
|
|||
|
|
@ -16,6 +16,30 @@ from ....tw.addresses import TwAddresses
|
|||
|
||||
from .view import MoneroTwView
|
||||
|
||||
async def add_new_address(parent, spec, ok_msg):
|
||||
from ....ui import line_input, keypress_confirm
|
||||
from ....color import green, yellow
|
||||
from ....xmrwallet import op as xmrwallet_op
|
||||
lbl = line_input(
|
||||
parent.cfg,
|
||||
'Enter label text for new address (or ENTER for default label): ')
|
||||
add_timestr = keypress_confirm(parent.cfg, 'Add timestamp to label?')
|
||||
op = xmrwallet_op(
|
||||
'new',
|
||||
parent.cfg,
|
||||
None,
|
||||
None,
|
||||
spec = spec + (',' + lbl if lbl else ''),
|
||||
compat_call = True)
|
||||
op.c.call('close_wallet')
|
||||
if await op.main(add_timestr=add_timestr):
|
||||
await parent.get_data()
|
||||
parent.oneshot_msg = green(ok_msg)
|
||||
return 'redraw'
|
||||
else:
|
||||
parent.oneshot_msg = yellow('Operation cancelled')
|
||||
return False
|
||||
|
||||
class MoneroTwAddresses(MoneroTwView, TwAddresses):
|
||||
|
||||
include_empty = True
|
||||
|
|
@ -23,8 +47,10 @@ class MoneroTwAddresses(MoneroTwView, TwAddresses):
|
|||
|
||||
prompt_fs_repl = {'XMR': (
|
||||
(1, 'Filters: show [E]mpty addrs, [u]sed addrs, all [L]abels'),
|
||||
(3, 'Actions: [q]uit menu, add [l]abel, [R]efresh balances:'))}
|
||||
(3, 'Actions: [q]uit menu, add [l]abel, [N]ew acct, [n]ew addr, [R]efresh bals:'))}
|
||||
extra_key_mappings = {
|
||||
'N': 'a_acct_new',
|
||||
'n': 'i_addr_new',
|
||||
'u': 'd_showused',
|
||||
'R': 'a_sync_wallets'}
|
||||
removed_key_mappings = {
|
||||
|
|
@ -40,3 +66,36 @@ class MoneroTwAddresses(MoneroTwView, TwAddresses):
|
|||
|
||||
def get_disp_data(self):
|
||||
return MoneroTwView.get_disp_data(self, input_data=tuple(TwAddresses.get_disp_data(self)))
|
||||
|
||||
class action(MoneroTwView.action):
|
||||
|
||||
async def a_acct_new(self, parent):
|
||||
from ....obj import Int
|
||||
from ....util import suf
|
||||
from ....addr import MMGenID
|
||||
from ....ui import item_chooser
|
||||
def wallet_id(wnum):
|
||||
return MMGenID(proto=parent.proto, id_str='{}:M:{}'.format(parent.sid, wnum))
|
||||
res = item_chooser(
|
||||
parent.cfg,
|
||||
'Choose a wallet to add a new account to',
|
||||
[(d['wallet_num'], len(d['data'].accts_data['subaddress_accounts']))
|
||||
for d in parent.dump_data],
|
||||
lambda d: '{a} [{b} account{c}]'.format(
|
||||
a = wallet_id(d[0]).hl(),
|
||||
b = Int(d[1]).hl(),
|
||||
c = suf(d[1])))
|
||||
return await add_new_address(
|
||||
parent,
|
||||
str(res.item[0]),
|
||||
f'New account added to wallet {wallet_id(res.item[0]).hl()}')
|
||||
|
||||
class item_action(TwAddresses.item_action):
|
||||
acct_methods = ('i_addr_new')
|
||||
|
||||
async def i_addr_new(self, parent, idx, acct_addr_idx=None):
|
||||
e = parent.accts_data[idx-1]
|
||||
return await add_new_address(
|
||||
parent,
|
||||
f'{e.idx}:{e.acct_idx}',
|
||||
f'New address added to wallet {e.idx}, account #{e.acct_idx}')
|
||||
|
|
|
|||
|
|
@ -57,16 +57,16 @@ class MoneroTwView:
|
|||
|
||||
op = xmrwallet_op('dump_data', self.cfg, None, None, compat_call=True)
|
||||
await op.restart_wallet_daemon()
|
||||
wallets_data = await op.main()
|
||||
self.dump_data = await op.main()
|
||||
|
||||
if wallets_data:
|
||||
self.sid = SeedID(sid=wallets_data[0]['seed_id'])
|
||||
if self.dump_data:
|
||||
self.sid = SeedID(sid=self.dump_data[0]['seed_id'])
|
||||
|
||||
self.total = self.unlocked_total = self.proto.coin_amt('0')
|
||||
|
||||
def gen_addrs():
|
||||
bd = namedtuple('address_balance_data', ['bal', 'unlocked_bal', 'blocks_to_unlock'])
|
||||
for wdata in wallets_data:
|
||||
for wdata in self.dump_data:
|
||||
bals_data = {i: {} for i in range(len(wdata['data'].accts_data['subaddress_accounts']))}
|
||||
|
||||
for d in wdata['data'].bals_data.get('per_subaddress', []):
|
||||
|
|
|
|||
|
|
@ -27,14 +27,16 @@ class OpNew(OpMixinSpec, OpWallet):
|
|||
spec_key = ((1, 'source'),)
|
||||
wallet_offline = True
|
||||
|
||||
async def main(self):
|
||||
async def main(self, add_timestr=True):
|
||||
h = MoneroWalletRPC(self, self.source)
|
||||
h.open_wallet('Monero', refresh=False)
|
||||
|
||||
desc = 'account' if self.account is None else 'address'
|
||||
label = TwComment(
|
||||
None if self.label == '' else
|
||||
'{} [{}]'.format(self.label or f'xmrwallet new {desc}', make_timestr()))
|
||||
'{a}{b}'.format(
|
||||
a = self.label or (f'new {desc}' if self.compat_call else f'xmrwallet new {desc}'),
|
||||
b = ' [{}]'.format(make_timestr()) if add_timestr else ''))
|
||||
|
||||
wallet_data = h.get_wallet_data()
|
||||
|
||||
|
|
@ -58,11 +60,14 @@ class OpNew(OpMixinSpec, OpWallet):
|
|||
|
||||
if desc == 'address':
|
||||
h.print_acct_addrs(wallet_data, self.account)
|
||||
ret = True
|
||||
else:
|
||||
ymsg('\nOperation cancelled by user request')
|
||||
ret = False
|
||||
|
||||
# wallet must be left open: otherwise the 'stop_wallet' RPC call used to stop the daemon will fail
|
||||
if self.cfg.no_stop_wallet_daemon:
|
||||
h.close_wallet('Monero')
|
||||
|
||||
msg('')
|
||||
return ret
|
||||
|
|
|
|||
|
|
@ -508,6 +508,7 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
|
|||
Monero autosigning operations (compat mode)
|
||||
"""
|
||||
menu_prompt = 'efresh balances:\b'
|
||||
listaddresses_menu_prompt = 'efresh bals:\b'
|
||||
extra_daemons = ['ltc']
|
||||
|
||||
cmd_group = (
|
||||
|
|
@ -548,6 +549,14 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
|
|||
('wait_loop_start_ltc', 'starting autosign wait loop in XMR compat mode [--coins=ltc,xmr]'),
|
||||
('alice_txsend1', 'sending the transaction'),
|
||||
('wait_loop_kill', 'stopping autosign wait loop'),
|
||||
('alice_newacct1', 'adding account to Alice’s tracking wallet (dfl label)'),
|
||||
('alice_newacct2', 'adding account to Alice’s tracking wallet (no timestr)'),
|
||||
('alice_newacct3', 'adding account to Alice’s tracking wallet'),
|
||||
('alice_newacct4', 'adding account to Alice’s tracking wallet (dfl label, no timestr)'),
|
||||
('alice_newaddr1', 'adding address to Alice’s tracking wallet'),
|
||||
('alice_newaddr2', 'adding address to Alice’s tracking wallet (no timestr)'),
|
||||
('alice_newaddr3', 'adding address to Alice’s tracking wallet (dfl label)'),
|
||||
('alice_newaddr4', 'adding address to Alice’s tracking wallet (dfl label, no timestr)'),
|
||||
('stop_daemons', 'stopping all wallet and coin daemons'),
|
||||
)
|
||||
|
||||
|
|
@ -600,6 +609,46 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
|
|||
addr_data = data['MoneroMMGenWalletDumpFile']['data']['wallet_metadata'][1]['addresses']
|
||||
return await self.fund_alice(addr=addr_data[addr_num-1]['address'], amt=amt)
|
||||
|
||||
def alice_newacct1(self):
|
||||
return self._alice_newacct(2, lbl_text='New Test Account', add_timestr=True)
|
||||
|
||||
def alice_newacct2(self):
|
||||
return self._alice_newacct(1, lbl_text='New Test Account')
|
||||
|
||||
def alice_newacct3(self):
|
||||
return self._alice_newacct(2, add_timestr=True)
|
||||
|
||||
def alice_newacct4(self):
|
||||
return self._alice_newacct(2)
|
||||
|
||||
def _alice_newacct(self, wallet_num, lbl_text='', add_timestr=False):
|
||||
return self._alice_twops(
|
||||
'listaddresses',
|
||||
newacct_wallet_num = wallet_num,
|
||||
lbl_text = lbl_text,
|
||||
add_timestr = add_timestr,
|
||||
expect_str = (lbl_text or 'new account ') + (r'.*\[20.*\]' if add_timestr else ''))
|
||||
|
||||
def alice_newaddr1(self):
|
||||
return self._alice_newaddr(1, lbl_text='New Test Address', add_timestr=True)
|
||||
|
||||
def alice_newaddr2(self):
|
||||
return self._alice_newaddr(1, lbl_text='New Test Address')
|
||||
|
||||
def alice_newaddr3(self):
|
||||
return self._alice_newaddr(2, add_timestr=True)
|
||||
|
||||
def alice_newaddr4(self):
|
||||
return self._alice_newaddr(2)
|
||||
|
||||
def _alice_newaddr(self, acct_num, lbl_text='', add_timestr=False):
|
||||
return self._alice_twops(
|
||||
'listaddresses',
|
||||
newaddr_acct_num = acct_num,
|
||||
lbl_text = lbl_text,
|
||||
add_timestr = add_timestr,
|
||||
expect_str = (lbl_text or 'new address ') + (r'.*\[20.*\]' if add_timestr else ''))
|
||||
|
||||
def alice_listaddresses(self):
|
||||
return self._alice_twops('listaddresses', menu='R')
|
||||
|
||||
|
|
@ -646,6 +695,8 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
|
|||
*,
|
||||
lbl_acct_num = None,
|
||||
lbl_addr_idx = None,
|
||||
newacct_wallet_num = None,
|
||||
newaddr_acct_num = None,
|
||||
lbl_text = '',
|
||||
add_timestr = False,
|
||||
menu = '',
|
||||
|
|
@ -660,16 +711,25 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
|
|||
+ self.autosign_opts
|
||||
+ [op]
|
||||
+ (['interactive=1'] if interactive else []))
|
||||
menu_prompt = self.menu_prompt
|
||||
have_lbl = lbl_acct_num
|
||||
menu_prompt = self.listaddresses_menu_prompt if op == 'listaddresses' else self.menu_prompt
|
||||
have_lbl = lbl_acct_num or newacct_wallet_num or newaddr_acct_num
|
||||
have_new_addr = newacct_wallet_num or newaddr_acct_num
|
||||
if interactive:
|
||||
if lbl_acct_num:
|
||||
t.expect(menu_prompt, 'l')
|
||||
t.expect('main menu): ', str(lbl_acct_num))
|
||||
t.expect('main menu): ', str(lbl_addr_idx))
|
||||
elif newacct_wallet_num:
|
||||
t.expect(menu_prompt, 'N')
|
||||
t.expect('number> ', f'{newacct_wallet_num}\n')
|
||||
elif newaddr_acct_num:
|
||||
t.expect(menu_prompt, 'n')
|
||||
t.expect('main menu): ', str(newaddr_acct_num))
|
||||
if have_lbl:
|
||||
t.expect(': ', lbl_text + '\n') # add label
|
||||
t.expect('(y/N): ', ('y' if add_timestr else 'n')) # add timestr
|
||||
if have_new_addr:
|
||||
t.expect('(y/N): ', 'y')
|
||||
for ch in menu:
|
||||
t.expect(menu_prompt, ch)
|
||||
if expect_str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue