tracking wallet classes: various cleanups

This commit is contained in:
The MMGen Project 2022-11-11 09:48:57 +00:00
commit 03712efbfb
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
12 changed files with 139 additions and 108 deletions

View file

@ -273,12 +273,12 @@ class Int(int,Hilite,InitErrors):
return cls.init_fail(e,n)
@classmethod
def fmtc(cls,*args,**kwargs):
cls.method_not_implemented()
def fmtc(cls,n,*args,**kwargs):
return super().fmtc(str(n),*args,**kwargs)
@classmethod
def colorize(cls,n,**kwargs):
return super().colorize(repr(n),**kwargs)
def colorize(cls,n,*args,**kwargs):
return super().colorize(str(n),*args,**kwargs)
class NonNegativeInt(Int):
min_val = 0

View file

@ -45,10 +45,10 @@ Actions: [q]uit, r[e]draw, add [l]abel:
'p':'a_print_detail',
'l':'a_comment_add' }
squeezed_fs_fs = ' {{n:>{nw}}} {{m:}} {{u:}}%s {{c:}} {{b:}} {{d:}}'
squeezed_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}} {{u:{uw}}}%s {{c:{cw}}} {{b:{bw}}} {{d:}}'
wide_fs_fs = ' {{n:>{nw}}} {{m:}} {{u:}} {{a:}} {{c:}} {{b:}} {{B:<{Bw}}} {{d:}}'
wide_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}} {{u:{uw}}} {{a:{aw}}} {{c:{cw}}} {{b:{bw}}} {{B:{Bw}}} {{d:}}'
squeezed_fs_fs = ' {{n:>{nw}}} {{m}} {{u}}%s {{c}} {{A}} {{d}}'
squeezed_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}} {{u:{uw}}}%s {{c:{cw}}} {{A:{Aw}}} {{d}}'
wide_fs_fs = ' {{n:>{nw}}} {{m}} {{u}} {{a}} {{c}} {{A}} {{b:<{bw}}} {{D}}'
wide_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}} {{u:{uw}}} {{a:{aw}}} {{c:{cw}}} {{A:{Aw}}} {{b:{bw}}} {{D}}'
async def get_rpc_data(self):

View file

@ -129,11 +129,11 @@ class BitcoinTwTransaction(BitcoinTwCommon):
def age_disp(self,age_fmt,width,color):
if age_fmt == 'confs':
ret_str = str(self.confirmations).rjust(width)
ret_str = str(self.confirmations).ljust(width)
return gray(ret_str) if self.confirmations < 0 and color else ret_str
elif age_fmt == 'block':
ret = (self.rpc.blockcount - (abs(self.confirmations) - 1)) * (-1 if self.confirmations < 0 else 1)
ret_str = str(ret).rjust(width)
ret_str = str(ret).ljust(width)
return gray(ret_str) if ret < 0 and color else ret_str
else:
return self.parent.date_formatter[age_fmt](self.rpc,self.tx.get('blocktime',0))
@ -253,8 +253,8 @@ Actions: [q]uit, r[e]draw:
'p':'a_print_squeezed',
'P':'a_print_detail' }
squeezed_fs_fs = ' {{n:>{nw}}} {{d:>{dw}}} {txid_fs}{{a1}} {{A}} {{a2}} {{l}}'
squeezed_hdr_fs_fs = ' {{n:>{nw}}} {{d:{dw}}} {txid_fs}{{a1:{aw}}} {{A}} {{a2:{a2w}}} {{l}}'
squeezed_fs_fs = ' {{n:>{nw}}} {{d:>{dw}}} {txid_fs}{{i}} {{A}} {{o}} {{c}}'
squeezed_hdr_fs_fs = ' {{n:>{nw}}} {{d:{dw}}} {txid_fs}{{i:{iw}}} {{A}} {{o:{ow}}} {{c}}'
async def get_rpc_data(self):
blockhash = (

View file

@ -17,7 +17,7 @@ from ....tw.ctl import TrackingWallet
from ....addr import CoinAddr
from .common import EthereumTwCommon
class EthereumTwAddresses(TwAddresses,EthereumTwCommon):
class EthereumTwAddresses(EthereumTwCommon,TwAddresses):
has_age = False
prompt = """
@ -40,10 +40,10 @@ Actions: [q]uit, r[e]draw, [D]elete address, add [l]abel:
'w':'a_view_detail',
'p':'a_print_detail' }
squeezed_fs_fs = ' {{n:>{nw}}} {{m:}}%s {{c:}} {{b:}}'
squeezed_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}}%s {{c:{cw}}} {{b:{bw}}}'
wide_fs_fs = ' {{n:>{nw}}} {{m:}} {{a:}} {{c:}} {{b:}}'
wide_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}} {{a:{aw}}} {{c:{cw}}} {{b:{bw}}}'
squeezed_fs_fs = ' {{n:>{nw}}} {{m:}}%s {{c:}} {{A:}}'
squeezed_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}}%s {{c:{cw}}} {{A:{Aw}}}'
wide_fs_fs = ' {{n:>{nw}}} {{m:}} {{a:}} {{c:}} {{A:}}'
wide_hdr_fs_fs = ' {{n:>{nw}}} {{m:{mw}}} {{a:{aw}}} {{c:{cw}}} {{A:{Aw}}}'
async def get_rpc_data(self):

View file

@ -11,12 +11,29 @@
"""
proto.eth.tw.common: Ethereum base protocol tracking wallet dependency classes
"""
from ....globalvars import g
from ....tw.ctl import TrackingWallet
from ....tw.common import TwCommon
from ....addr import CoinAddr
from ....tw.common import TwLabel
class EthereumTwCommon:
class EthereumTwCommon(TwCommon):
def age_disp(self,o,age_fmt): # TODO
pass
def get_disp_prec(self,wide):
return self.proto.coin_amt.max_prec if wide else 8
def subheader(self,color):
ret = ''
if self.disp_prec == 8:
ret += 'Balances truncated to 8 decimal points\n'
if g.cached_balances:
from ....color import nocolor,yellow
ret += (nocolor,yellow)[color](
'WARNING: Using cached balances. These may be out of date!') + '\n'
return ret
async def get_addr_label_pairs(self,twmmid=None):
wallet = (

View file

@ -27,7 +27,7 @@ from ....amt import ETHAmt
from ..contract import Token,TokenResolve
from .common import EthereumTwCommon
class EthereumTrackingWallet(TrackingWallet,EthereumTwCommon):
class EthereumTrackingWallet(EthereumTwCommon,TrackingWallet):
caps = ('batch',)
data_key = 'accounts'

View file

@ -100,10 +100,6 @@ class EthereumTokenTwUnspentOutputs(EthereumTwUnspentOutputs):
await super().__init__(proto,*args,**kwargs)
self.proto.tokensym = self.wallet.symbol
@property
def disp_prec(self):
return 10 # truncate precision for narrow display
async def get_data(self,*args,**kwargs):
await super().get_data(*args,**kwargs)
for e in self.data:

View file

@ -12,12 +12,10 @@
tw.addresses: Tracking wallet listaddresses class for the MMGen suite
"""
from collections import namedtuple
from ..util import suf
from ..base_obj import AsyncInit
from ..objmethods import MMGenObject
from ..obj import MMGenList,MMGenListItem,ImmutableAttr,ListItemAttr,TwComment,NonNegativeInt
from ..obj import MMGenListItem,ImmutableAttr,ListItemAttr,TwComment,NonNegativeInt
from ..rpc import rpc_init
from ..addr import CoinAddr,MMGenID
from ..color import red,green
@ -30,7 +28,6 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
item_desc = 'address'
txid_w = 64
sort_key = 'twmmid'
age_fmts_interactive = ('confs','block','days','date','date_time')
update_widths_on_age_toggle = True
print_output_types = ('detail',)
filters = ('showempty','showused','all_labels')
@ -133,15 +130,17 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
'mmid': max(len(d.twmmid.disp) for d in data),
'used': 4,
'amt': self.disp_prec + 5,
'date': self.age_w,
'date': self.age_w if self.has_age else 0,
'block': self.age_col_params['block'][0] if wide and self.has_age else 0,
'date_time': self.age_col_params['date_time'][0] if wide and self.has_age else 0,
'spc': 7, # 6 spaces between cols + 1 leading space in fs
},
maxws = { # expandable cols
'addr': max(len(d.addr) for d in data),
'addr': max(len(d.addr) for d in data) if self.showcoinaddrs else 0,
'comment': max(d.comment.screen_width for d in data),
},
minws = {
'addr': 12,
'addr': 12 if self.showcoinaddrs else 0,
'comment': len('Comment'),
},
maxws_nice = {'addr': 18},
@ -162,12 +161,12 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
'uw': cw.used,
'aw': cw.addr,
'cw': cw.comment,
'bw': cw.amt,
'Aw': cw.amt,
'dw': cw.date
}
hdr_fs = (self.squeezed_hdr_fs_fs % ('',' {{a:{aw}}}')[self.showcoinaddrs]).format(**fs_parms)
fs = (self.squeezed_fs_fs % ('',' {{a:}}')[self.showcoinaddrs]).format(**fs_parms)
fs = (self.squeezed_fs_fs % ('',' {{a}}')[self.showcoinaddrs]).format(**fs_parms)
yield hdr_fs.format(
n = '',
@ -175,7 +174,7 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
u = 'Used',
a = 'Address',
c = 'Comment',
b = 'Balance',
A = 'Balance',
d = self.age_hdr )
yes,no = (red('Yes '),green('No ')) if color else ('Yes ','No ')
@ -187,11 +186,11 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
yield ''
yield fs.format(
n = str(n) + ')',
m = MMGenID.fmtc(d.twmmid.disp,width=cw.mmid,color=True),
m = d.twmmid.fmt(width=cw.mmid,color=color),
u = yes if d.recvd else no,
a = d.addr.fmt(color=True,width=cw.addr),
c = d.comment.fmt(width=cw.comment,color=True,nullrepl='-'),
b = d.amt.fmt(color=True),
a = d.addr.fmt(color=color,width=cw.addr),
c = d.comment.fmt(width=cw.comment,color=color,nullrepl='-'),
A = d.amt.fmt(color=color,prec=self.disp_prec),
d = self.age_disp( d, self.age_fmt )
)
@ -203,9 +202,9 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
'uw': cw.used,
'aw': cw.addr,
'cw': cw.comment,
'bw': cw.amt,
'Bw': self.age_col_params['block'][0],
'dw': self.age_col_params['date_time'][0],
'Aw': cw.amt,
'bw': self.age_col_params['block'][0],
'Dw': self.age_col_params['date_time'][0],
}
hdr_fs = self.wide_hdr_fs_fs.format(**fs_parms)
@ -217,9 +216,9 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
u = 'Used',
a = 'Address',
c = 'Comment',
b = 'Balance',
B = 'Block',
d = 'Date' )
A = 'Balance',
b = 'Block',
D = 'Date/Time' ).rstrip()
yes,no = (red('Yes '),green('No ')) if color else ('Yes ','No ')
id_save = data[0].al_id
@ -230,14 +229,14 @@ class TwAddresses(MMGenObject,TwCommon,metaclass=AsyncInit):
yield ''
yield fs.format(
n = str(n) + ')',
m = MMGenID.fmtc(d.twmmid.disp,width=fs_parms['mw'],color=color),
m = d.twmmid.fmt(width=cw.mmid,color=color),
u = yes if d.recvd else no,
a = d.addr.fmt(color=color,width=fs_parms['aw']),
c = d.comment.fmt(width=fs_parms['cw'],color=color,nullrepl='-'),
b = d.amt.fmt(color=color),
B = self.age_disp( d, 'block' ),
d = self.age_disp( d, 'date_time' ),
)
a = d.addr.fmt(color=color,width=cw.addr),
c = d.comment.fmt(width=cw.comment,color=color,nullrepl='-'),
A = d.amt.fmt(color=color,prec=self.disp_prec),
b = self.age_disp( d, 'block' ),
D = self.age_disp( d, 'date_time' ),
).rstrip()
async def set_dates(self,addrs):
if not self.dates_set:

View file

@ -44,7 +44,7 @@ class TwCommon:
age_fmts = ('confs','block','days','date','date_time')
age_fmts_date_dependent = ('days','date','date_time')
age_fmts_interactive = ('confs','block','days','date')
age_fmts_interactive = ('confs','block','days','date','date_time')
_age_fmt = 'confs'
age_col_params = {
@ -138,8 +138,7 @@ class TwCommon:
f'{val!r}: invalid age format for {op_desc} operation (must be one of {ok_vals!r})' )
self._age_fmt = val
@property
def disp_prec(self):
def get_disp_prec(self,wide):
return self.proto.coin_amt.max_prec
def get_term_columns(self,min_cols):
@ -277,6 +276,8 @@ class TwCommon:
dt = getattr(self.display_type,display_type)
self.disp_prec = self.get_disp_prec(wide=dt.detail)
if self.has_age and (self.age_fmt in self.age_fmts_date_dependent or dt.detail):
await self.set_dates(self.data)
@ -509,6 +510,10 @@ class TwMMGenID(str,Hilite,InitErrors,MMGenObject):
me.proto = proto
return me
@classmethod
def fmtc(cls,twmmid,*args,**kwargs):
return super().fmtc(twmmid.disp,*args,**kwargs)
# non-displaying container for TwMMGenID,TwComment
class TwLabel(str,InitErrors,MMGenObject):
exc = 'BadTwLabel'

View file

@ -36,7 +36,6 @@ class TwTxHistory(MMGenObject,TwCommon,metaclass=AsyncInit):
show_txid = False
show_unconfirmed = False
show_total_amt = False
age_fmts_interactive = ('confs','block','days','date','date_time')
update_widths_on_age_toggle = True
print_output_types = ('squeezed','detail')
filters = ('show_unconfirmed',)
@ -56,18 +55,18 @@ class TwTxHistory(MMGenObject,TwCommon,metaclass=AsyncInit):
def get_column_widths(self,data,wide=False):
# var cols: addr1 addr2 comment [txid]
# var cols: inputs outputs comment [txid]
if not hasattr(self,'varcol_maxwidths'):
self.varcol_maxwidths = {
'addr1': max(len(d.vouts_disp('inputs',width=None,color=False)) for d in data),
'addr2': max(len(d.vouts_disp('outputs',width=None,color=False)) for d in data),
'inputs': max(len(d.vouts_disp('inputs',width=None,color=False)) for d in data),
'outputs': max(len(d.vouts_disp('outputs',width=None,color=False)) for d in data),
'comment': max(len(d.comment) for d in data),
}
maxws = self.varcol_maxwidths.copy()
minws = {
'addr1': 15,
'addr2': 15,
'inputs': 15,
'outputs': 15,
'comment': len('Comment'),
}
if self.show_txid:
@ -75,11 +74,13 @@ class TwTxHistory(MMGenObject,TwCommon,metaclass=AsyncInit):
minws['txid'] = 8
maxws_nice = {'txid': 20}
else:
maxws['txid'] = 0
minws['txid'] = 0
maxws_nice = {}
widths = { # fixed cols
'num': max(2,len(str(len(data)))+1),
'age': self.age_w,
'date': self.age_w,
'amt': self.disp_prec + 5,
'spc': 6 + self.show_txid, # 5(6) spaces between cols + 1 leading space in fs
}
@ -92,8 +93,8 @@ class TwTxHistory(MMGenObject,TwCommon,metaclass=AsyncInit):
yield f'Displaying transactions since block {self.sinceblock.hl(color=color)}'
yield 'Only wallet-related outputs are shown'
yield 'Comment is from first wallet address in outputs or inputs'
if (cw.addr1 < self.varcol_maxwidths['addr1'] or
cw.addr2 < self.varcol_maxwidths['addr2'] ):
if (cw.inputs < self.varcol_maxwidths['inputs'] or
cw.outputs < self.varcol_maxwidths['outputs'] ):
yield 'Due to screen width limitations, not all addresses could be displayed'
yield ''
@ -101,8 +102,8 @@ class TwTxHistory(MMGenObject,TwCommon,metaclass=AsyncInit):
nw = cw.num,
dw = self.age_w,
txid_fs = f'{{i:{cw.txid}}} ' if self.show_txid else '',
aw = cw.addr1,
a2w = cw.addr2 )
iw = cw.inputs,
ow = cw.outputs )
fs = self.squeezed_fs_fs.format(
nw = cw.num,
@ -110,58 +111,56 @@ class TwTxHistory(MMGenObject,TwCommon,metaclass=AsyncInit):
txid_fs = f'{{i:{cw.txid}}} ' if self.show_txid else '' )
yield hdr_fs.format(
n = '',
i = 'TxID',
d = self.age_hdr,
a1 = 'Inputs',
A = 'Amt({})'.format('TX' if self.show_total_amt else 'Wallet').ljust(cw.amt),
a2 = 'Outputs',
l = 'Comment' ).rstrip()
n = '',
t = 'TxID',
d = self.age_hdr,
i = 'Inputs',
A = 'Amt({})'.format('TX' if self.show_total_amt else 'Wallet'),
o = 'Outputs',
c = 'Comment' ).rstrip()
for n,d in enumerate(data,1):
yield fs.format(
n = str(n) + ')',
i = d.txid_disp( width=cw.txid, color=color ) if hasattr(cw,'txid') else None,
d = d.age_disp( self.age_fmt, width=self.age_w, color=color ),
a1 = d.vouts_disp( 'inputs', width=cw.addr1, color=color ),
A = d.amt_disp(self.show_total_amt).fmt( prec=self.disp_prec, color=color ),
a2 = d.vouts_disp( 'outputs', width=cw.addr2, color=color ),
l = d.comment.fmt( width=cw.comment, color=color ) ).rstrip()
n = str(n) + ')',
t = d.txid_disp( width=cw.txid, color=color ) if hasattr(cw,'txid') else None,
d = d.age_disp( self.age_fmt, width=self.age_w, color=color ),
i = d.vouts_disp( 'inputs', width=cw.inputs, color=color ),
A = d.amt_disp(self.show_total_amt).fmt( prec=self.disp_prec, color=color ),
o = d.vouts_disp( 'outputs', width=cw.outputs, color=color ),
c = d.comment.fmt( width=cw.comment, color=color ) ).rstrip()
def gen_detail_display(self,data,cw,color):
yield (
(f'Displaying transactions since block {self.sinceblock.hl(color=color)}\n'
if self.sinceblock else '')
+ 'Only wallet-related outputs are shown'
)
if self.sinceblock:
yield f'Displaying transactions since block {self.sinceblock.hl(color=color)}'
yield 'Only wallet-related outputs are shown'
fs = fmt("""
{n}
Block: [{d}] {b}
TxID: [{D}] {i}
Value: {A1}
Wallet Value: {A2}
TxID: [{D}] {t}
Value: {A}
Wallet Value: {B}
Fee: {f}
Inputs:
{a1}
Outputs ({oc}):
{a2}
{i}
Outputs ({N}):
{o}
""",strip_char='\t').strip()
for n,d in enumerate(data,1):
yield fs.format(
n = str(n) + ')',
d = d.age_disp( 'date_time', width=None, color=None ),
b = d.blockheight_disp(color=color),
D = d.txdate_disp( 'date_time' ),
i = d.txid_disp( width=None, color=color ),
A1 = d.amt_disp(True).hl( color=color ),
A2 = d.amt_disp(False).hl( color=color ),
f = d.fee_disp( color=color ),
a1 = d.vouts_list_disp( 'inputs', color=color, indent=' '*8 ),
oc = d.nOutputs,
a2 = d.vouts_list_disp( 'outputs', color=color, indent=' '*8 ),
n = str(n) + ')',
d = d.age_disp( 'date_time', width=None, color=None ),
b = d.blockheight_disp(color=color),
D = d.txdate_disp( 'date_time' ),
t = d.txid_disp( width=None, color=color ),
A = d.amt_disp(True).hl( color=color ),
B = d.amt_disp(False).hl( color=color ),
f = d.fee_disp( color=color ),
i = d.vouts_list_disp( 'inputs', color=color, indent=' '*8 ),
N = d.nOutputs,
o = d.vouts_list_disp( 'outputs', color=color, indent=' '*8 ),
)
sort_disp = {

View file

@ -20,15 +20,21 @@
twuo: Tracking wallet unspent outputs class for the MMGen suite
"""
import asyncio
from collections import namedtuple
from ..globalvars import g
from ..color import red,yellow
from ..util import msg,die,capfirst,suf,fmt
from ..util import msg,suf,fmt
from ..base_obj import AsyncInit
from ..objmethods import MMGenObject
from ..obj import ImmutableAttr,ListItemAttr,MMGenListItem,TwComment,get_obj,HexStr,CoinTxID,MMGenList
from ..obj import (
ImmutableAttr,
ListItemAttr,
MMGenListItem,
TwComment,
get_obj,
HexStr,
CoinTxID,
NonNegativeInt )
from ..addr import CoinAddr,MMGenID
from ..rpc import rpc_init
from .common import TwCommon,TwMMGenID,get_tw_label
@ -48,7 +54,7 @@ class TwUnspentOutputs(MMGenObject,TwCommon,metaclass=AsyncInit):
class MMGenTwUnspentOutput(MMGenListItem):
txid = ListItemAttr(CoinTxID)
vout = ListItemAttr(int,typeconv=False)
vout = ListItemAttr(NonNegativeInt)
amt = ImmutableAttr(None)
amt2 = ListItemAttr(None) # the ETH balance for token account
comment = ListItemAttr(TwComment,reassign_ok=True)

View file

@ -14,13 +14,22 @@ tx.base: base transaction class
from ..globalvars import *
from ..objmethods import MMGenObject
from ..obj import ImmutableAttr,ListItemAttr,MMGenListItem,MMGenTxComment,TwComment,CoinTxID,HexStr
from ..obj import (
ImmutableAttr,
ListItemAttr,
MMGenListItem,
MMGenTxComment,
TwComment,
CoinTxID,
HexStr,
NonNegativeInt
)
from ..addr import MMGenID,CoinAddr
from ..util import msg,ymsg,fmt,remove_dups,make_timestamp,die
from ..opts import opt
class MMGenTxIO(MMGenListItem):
vout = ListItemAttr(int,typeconv=False)
vout = ListItemAttr(NonNegativeInt)
amt = ImmutableAttr(None)
comment = ListItemAttr(TwComment,reassign_ok=True)
mmid = ListItemAttr(MMGenID,include_proto=True)