mmgen-tool twimport,twexport: support Ethereum
This commit is contained in:
parent
a51352d5b7
commit
72aef8b02f
4 changed files with 209 additions and 4 deletions
|
|
@ -91,6 +91,9 @@ class EthereumTrackingWallet(TrackingWallet):
|
|||
async def batch_import_address(self,args_list):
|
||||
return [await self.import_address(*a) for a in args_list]
|
||||
|
||||
async def rescan_addresses(self,coin_addrs):
|
||||
pass
|
||||
|
||||
@write_mode
|
||||
async def import_address(self,addr,label):
|
||||
r = self.data_root
|
||||
|
|
@ -229,6 +232,3 @@ class EthereumTokenTrackingWallet(EthereumTrackingWallet):
|
|||
'decimals': t.decimals
|
||||
}
|
||||
}
|
||||
|
||||
async def twimport_check_and_create_wallet(self,info_msg):
|
||||
raise NotImplementedError('method not implemented for Ethereum')
|
||||
|
|
|
|||
145
mmgen/base_proto/ethereum/tw/json.py
Executable file
145
mmgen/base_proto/ethereum/tw/json.py
Executable file
|
|
@ -0,0 +1,145 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
|
||||
# Copyright (C)2013-2022 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen
|
||||
# https://gitlab.com/mmgen/mmgen
|
||||
|
||||
"""
|
||||
base_proto.ethereum.tw.json: export and import tracking wallet to JSON format
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
from ....tw.json import TwJSON
|
||||
from ....tw.common import TwMMGenID
|
||||
|
||||
class EthereumTwJSON(TwJSON):
|
||||
|
||||
class Base(TwJSON.Base):
|
||||
|
||||
def __init__(self,proto,*args,**kwargs):
|
||||
|
||||
self.params_keys = ['symbol','decimals']
|
||||
self.params_tuple = namedtuple('params_tuple',self.params_keys)
|
||||
|
||||
super().__init__(proto,*args,**kwargs)
|
||||
|
||||
@property
|
||||
def mappings_json(self):
|
||||
|
||||
def gen_mappings(data):
|
||||
for d in data:
|
||||
yield (d.mmgen_id,d.address) if hasattr(d,'mmgen_id') else d
|
||||
|
||||
return self.json_dump({
|
||||
'accounts': list(gen_mappings(self.entries['accounts'])),
|
||||
'tokens': {k:list(gen_mappings(v)) for k,v in self.entries['tokens'].items()}
|
||||
})
|
||||
|
||||
@property
|
||||
def num_entries(self):
|
||||
return len(self.entries['accounts']) + len(self.entries['tokens'])
|
||||
|
||||
class Import(TwJSON.Import,Base):
|
||||
|
||||
info_msg = """
|
||||
This utility will recreate a new tracking wallet from the supplied JSON dump.
|
||||
If the dump contains address balances, balances will be updated from it.
|
||||
"""
|
||||
|
||||
@property
|
||||
async def tracking_wallet_exists(self):
|
||||
return bool(self.tw.data['accounts'] or self.tw.data['tokens'])
|
||||
|
||||
async def create_tracking_wallet(self):
|
||||
return True
|
||||
|
||||
async def get_entries(self):
|
||||
|
||||
edata = self.data['data']['entries']
|
||||
|
||||
def gen_entries(data):
|
||||
for d in data:
|
||||
if len(d) == 2:
|
||||
yield self.params_tuple(*d)
|
||||
else:
|
||||
e = self.entry_tuple_in(*d)
|
||||
yield self.entry_tuple(
|
||||
TwMMGenID(self.proto,e.mmgen_id),
|
||||
e.address,
|
||||
getattr(e,'amount','0'),
|
||||
e.comment )
|
||||
|
||||
def gen_token_entries():
|
||||
for token_addr,token_data in edata['tokens'].items():
|
||||
yield (
|
||||
token_addr,
|
||||
list(gen_entries(token_data)),
|
||||
)
|
||||
|
||||
return {
|
||||
'accounts': list(gen_entries( edata['accounts'] )),
|
||||
'tokens': dict(list(gen_token_entries()))
|
||||
}
|
||||
|
||||
async def do_import(self,batch):
|
||||
|
||||
def gen_data(data):
|
||||
for d in data:
|
||||
if hasattr(d,'address'):
|
||||
if d.amount is None: # Python 3.9: {} | {}
|
||||
yield (d.address, {'mmid':d.mmgen_id,'comment':d.comment})
|
||||
else:
|
||||
yield (d.address, {'mmid':d.mmgen_id,'comment':d.comment,'balance':d.amount})
|
||||
else:
|
||||
yield ('params', {'symbol':d.symbol,'decimals':d.decimals})
|
||||
|
||||
self.tw.data = { # keys must be in correct order
|
||||
'coin': self.coin.upper(),
|
||||
'network': self.network.upper(),
|
||||
'accounts': dict(gen_data(self.entries['accounts'])),
|
||||
'tokens': {k:dict(gen_data(v)) for k,v in self.entries['tokens'].items()},
|
||||
}
|
||||
self.tw.write(quiet=False)
|
||||
|
||||
class Export(TwJSON.Export,Base):
|
||||
|
||||
async def get_entries(self,include_amts=True):
|
||||
|
||||
def gen_data(data):
|
||||
for k,v in data.items():
|
||||
if k == 'params':
|
||||
yield self.params_tuple(**v)
|
||||
elif include_amts:
|
||||
yield self.entry_tuple(TwMMGenID(self.proto,v['mmid']), k, v.get('balance'), v['comment'])
|
||||
else:
|
||||
yield self.entry_tuple_in(TwMMGenID(self.proto,v['mmid']), k, v['comment'])
|
||||
|
||||
def gen_token_data():
|
||||
for token_addr,token_data in self.tw.data['tokens'].items():
|
||||
yield (
|
||||
token_addr,
|
||||
sorted(
|
||||
gen_data(token_data),
|
||||
key = lambda x: x.mmgen_id.sort_key if hasattr(x,'mmgen_id') else '+'
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
'accounts': sorted(
|
||||
gen_data(self.tw.data['accounts']),
|
||||
key = lambda x: x.mmgen_id.sort_key ),
|
||||
'tokens': dict(sorted(gen_token_data()))
|
||||
}
|
||||
|
||||
@property
|
||||
async def entries_out(self):
|
||||
return await self.get_entries(include_amts='amount' in self.keys)
|
||||
|
||||
@property
|
||||
async def total(self):
|
||||
from ....amt import ETHAmt
|
||||
return sum(ETHAmt(i.amount) for i in self.entries['accounts']) or ETHAmt('0')
|
||||
|
|
@ -1 +1 @@
|
|||
13.2.dev6
|
||||
13.2.dev7
|
||||
|
|
|
|||
|
|
@ -307,6 +307,18 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
|
|||
('token_remove_addr1', f'removing addr #{del_addrs[0]} from {coin} token tracking wallet'),
|
||||
('token_remove_addr2', f'removing addr #{del_addrs[1]} from {coin} token tracking wallet'),
|
||||
|
||||
('twexport_noamt', 'exporting the tracking wallet (include_amts=0)'),
|
||||
('twmove', 'moving the tracking wallet'),
|
||||
('twimport', 'importing the tracking wallet'),
|
||||
('twview7', 'twview (cached_balances=1)'),
|
||||
('twview8', 'twview'),
|
||||
('twexport', 'exporting the tracking wallet'),
|
||||
('tw_chktotal', 'checking total value in tracking wallet dump'),
|
||||
('twmove', 'moving the tracking wallet'),
|
||||
('twimport', 'importing the tracking wallet'),
|
||||
('twcompare', 'comparing imported tracking wallet with original'),
|
||||
('twview9', 'twview (check balance)'),
|
||||
|
||||
('stop', 'stopping daemon'),
|
||||
)
|
||||
|
||||
|
|
@ -1205,6 +1217,12 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
|
|||
return self.twview(tool_args=['wide=1','minconf=0'])
|
||||
def twview6(self):
|
||||
return self.twview(expect_str=vbal6)
|
||||
def twview7(self):
|
||||
return self.twview(args=['--cached-balances'])
|
||||
def twview8(self):
|
||||
return self.twview()
|
||||
def twview9(self):
|
||||
return self.twview(args=['--cached-balances'],expect_str=vbal6)
|
||||
|
||||
def token_twview1(self):
|
||||
return self.twview(args=['--token=mm1'])
|
||||
|
|
@ -1248,6 +1266,48 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
|
|||
def token_remove_addr2(self):
|
||||
return self.edit_label(out_num=del_addrs[1],args=['--token=mm1'],action='D')
|
||||
|
||||
def twexport_noamt(self):
|
||||
return self.twexport(add_args=['include_amts=0'])
|
||||
|
||||
def twexport(self,add_args=[]):
|
||||
t = self.spawn('mmgen-tool', self.eth_args + ['twexport'] + add_args)
|
||||
t.written_to_file('JSON data')
|
||||
return t
|
||||
|
||||
async def twmove(self):
|
||||
self.spawn('',msg_only=True)
|
||||
from mmgen.tw.ctl import TrackingWallet
|
||||
tw = await TrackingWallet(self.proto)
|
||||
imsg(f'Moving tracking wallet')
|
||||
os.rename( tw.tw_fn, tw.tw_fn+'.bak.json' )
|
||||
return 'ok'
|
||||
|
||||
def twimport(self,add_args=[]):
|
||||
from mmgen.tw.json import TwJSON
|
||||
fn = joinpath( self.tmpdir, TwJSON.Base(self.proto).dump_fn )
|
||||
t = self.spawn('mmgen-tool',self.eth_args + ['twimport',fn] + add_args)
|
||||
t.expect('(y/N): ','y')
|
||||
t.written_to_file('tracking wallet data')
|
||||
return t
|
||||
|
||||
def tw_chktotal(self):
|
||||
self.spawn('',msg_only=True)
|
||||
from mmgen.tw.json import TwJSON
|
||||
fn = joinpath( self.tmpdir, TwJSON.Base(self.proto).dump_fn )
|
||||
res = json.loads(read_from_file(fn))
|
||||
cmp_or_die( res['data']['value'], vbal6, 'value in tracking wallet JSON dump' )
|
||||
return 'ok'
|
||||
|
||||
async def twcompare(self):
|
||||
self.spawn('',msg_only=True)
|
||||
from mmgen.tw.ctl import TrackingWallet
|
||||
tw = await TrackingWallet(self.proto)
|
||||
fn = tw.tw_fn
|
||||
imsg(f'Comparing imported tracking wallet with original')
|
||||
data = [json.dumps(json.loads(read_from_file(f)),sort_keys=True) for f in (fn,fn+'.bak.json')]
|
||||
cmp_or_die(*data,'tracking wallets')
|
||||
return 'ok'
|
||||
|
||||
def stop(self):
|
||||
self.spawn('',msg_only=True)
|
||||
if not opt.no_daemon_stop:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue