|
@@ -57,18 +57,6 @@ def get_obj(objname,*args,**kwargs):
|
|
|
else:
|
|
|
return True if return_bool else ret
|
|
|
|
|
|
-def is_addr_idx(s):
|
|
|
- return get_obj(AddrIdx, n=s, silent=True, return_bool=True)
|
|
|
-
|
|
|
-def is_addrlist_id(s):
|
|
|
- return get_obj(AddrListID, sid=s, silent=True, return_bool=True)
|
|
|
-
|
|
|
-def is_mmgen_id(proto,s):
|
|
|
- return get_obj(MMGenID, proto=proto, id_str=s, silent=True, return_bool=True)
|
|
|
-
|
|
|
-def is_coin_addr(proto,s):
|
|
|
- return get_obj(CoinAddr, proto=proto, addr=s, silent=True, return_bool=True)
|
|
|
-
|
|
|
# dict that keeps a list of keys for efficient lookup by index
|
|
|
class IndexedDict(dict):
|
|
|
|
|
@@ -268,9 +256,6 @@ class MMGenListItem(MMGenObject):
|
|
|
class MMGenIdx(Int):
|
|
|
min_val = 1
|
|
|
|
|
|
-class AddrIdx(MMGenIdx):
|
|
|
- max_digits = 7
|
|
|
-
|
|
|
class MMGenRange(tuple,InitErrors,MMGenObject):
|
|
|
|
|
|
min_idx = None
|
|
@@ -314,67 +299,6 @@ class MMGenRange(tuple,InitErrors,MMGenObject):
|
|
|
def items(self):
|
|
|
return list(self.iterate())
|
|
|
|
|
|
-class CoinAddr(str,Hilite,InitErrors,MMGenObject):
|
|
|
- color = 'cyan'
|
|
|
- hex_width = 40
|
|
|
- width = 1
|
|
|
- trunc_ok = False
|
|
|
- def __new__(cls,proto,addr):
|
|
|
- if type(addr) == cls:
|
|
|
- return addr
|
|
|
- try:
|
|
|
- assert set(addr) <= set(ascii_letters+digits),'contains non-alphanumeric characters'
|
|
|
- me = str.__new__(cls,addr)
|
|
|
- ap = proto.parse_addr(addr)
|
|
|
- assert ap, f'coin address {addr!r} could not be parsed'
|
|
|
- me.addr_fmt = ap.fmt
|
|
|
- me.hex = ap.bytes.hex()
|
|
|
- me.proto = proto
|
|
|
- return me
|
|
|
- except Exception as e:
|
|
|
- return cls.init_fail(e,addr,objname=f'{proto.cls_name} address')
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def fmtc(cls,addr,**kwargs):
|
|
|
- w = kwargs['width'] or cls.width
|
|
|
- return super().fmtc(addr[:w-2]+'..' if w < len(addr) else addr, **kwargs)
|
|
|
-
|
|
|
-class TokenAddr(CoinAddr):
|
|
|
- color = 'blue'
|
|
|
-
|
|
|
-class ViewKey(object):
|
|
|
- def __new__(cls,proto,viewkey):
|
|
|
- if proto.name == 'Zcash':
|
|
|
- return ZcashViewKey.__new__(ZcashViewKey,proto,viewkey)
|
|
|
- elif proto.name == 'Monero':
|
|
|
- return MoneroViewKey.__new__(MoneroViewKey,viewkey)
|
|
|
- else:
|
|
|
- raise ValueError(f'{proto.name}: protocol does not support view keys')
|
|
|
-
|
|
|
-class ZcashViewKey(CoinAddr): hex_width = 128
|
|
|
-
|
|
|
-class MMGenID(str,Hilite,InitErrors,MMGenObject):
|
|
|
- color = 'orange'
|
|
|
- width = 0
|
|
|
- trunc_ok = False
|
|
|
- def __new__(cls,proto,id_str):
|
|
|
- from .seed import SeedID
|
|
|
- try:
|
|
|
- ss = str(id_str).split(':')
|
|
|
- assert len(ss) in (2,3),'not 2 or 3 colon-separated items'
|
|
|
- t = proto.addr_type((ss[1],proto.dfl_mmtype)[len(ss)==2])
|
|
|
- me = str.__new__(cls,'{}:{}:{}'.format(ss[0],t,ss[-1]))
|
|
|
- me.sid = SeedID(sid=ss[0])
|
|
|
- me.idx = AddrIdx(ss[-1])
|
|
|
- me.mmtype = t
|
|
|
- assert t in proto.mmtypes, f'{t}: invalid address type for {proto.cls_name}'
|
|
|
- me.al_id = str.__new__(AddrListID,me.sid+':'+me.mmtype) # checks already done
|
|
|
- me.sort_key = '{}:{}:{:0{w}}'.format(me.sid,me.mmtype,me.idx,w=me.idx.max_digits)
|
|
|
- me.proto = proto
|
|
|
- return me
|
|
|
- except Exception as e:
|
|
|
- return cls.init_fail(e,id_str)
|
|
|
-
|
|
|
class TwMMGenID(str,Hilite,InitErrors,MMGenObject):
|
|
|
color = 'orange'
|
|
|
width = 0
|
|
@@ -383,6 +307,7 @@ class TwMMGenID(str,Hilite,InitErrors,MMGenObject):
|
|
|
if type(id_str) == cls:
|
|
|
return id_str
|
|
|
ret = None
|
|
|
+ from .addr import MMGenID
|
|
|
try:
|
|
|
ret = MMGenID(proto,id_str)
|
|
|
sort_key,idtype = ret.sort_key,'mmgen'
|
|
@@ -449,29 +374,9 @@ class CoinTxID(HexStr):
|
|
|
class WalletPassword(HexStr):
|
|
|
color,width,hexcase = ('blue',32,'lower')
|
|
|
|
|
|
-class MoneroViewKey(HexStr):
|
|
|
- color,width,hexcase = ('cyan',64,'lower') # FIXME - no checking performed
|
|
|
-
|
|
|
class MMGenTxID(HexStr):
|
|
|
color,width,hexcase = ('red',6,'upper')
|
|
|
|
|
|
-class AddrListID(str,Hilite,InitErrors,MMGenObject):
|
|
|
- width = 10
|
|
|
- trunc_ok = False
|
|
|
- color = 'yellow'
|
|
|
- def __new__(cls,sid,mmtype):
|
|
|
- from .seed import SeedID
|
|
|
- try:
|
|
|
- assert type(sid) == SeedID, f'{sid!r} not a SeedID instance'
|
|
|
- if not isinstance(mmtype,(MMGenAddrType,MMGenPasswordType)):
|
|
|
- raise ValueError(f'{mmtype!r}: not an instance of MMGenAddrType or MMGenPasswordType')
|
|
|
- me = str.__new__(cls,sid+':'+mmtype)
|
|
|
- me.sid = sid
|
|
|
- me.mmtype = mmtype
|
|
|
- return me
|
|
|
- except Exception as e:
|
|
|
- return cls.init_fail(e, f'sid={sid}, mmtype={mmtype}')
|
|
|
-
|
|
|
class MMGenLabel(str,Hilite,InitErrors):
|
|
|
color = 'pink'
|
|
|
allowed = []
|
|
@@ -535,60 +440,3 @@ class MMGenPWIDString(MMGenLabel):
|
|
|
desc = 'password ID string'
|
|
|
forbidden = list(' :/\\')
|
|
|
trunc_ok = False
|
|
|
-
|
|
|
-from collections import namedtuple
|
|
|
-ati = namedtuple('addrtype_info',
|
|
|
- ['name','pubkey_type','compressed','gen_method','addr_fmt','wif_label','extra_attrs','desc'])
|
|
|
-
|
|
|
-class MMGenAddrType(str,Hilite,InitErrors,MMGenObject):
|
|
|
- width = 1
|
|
|
- trunc_ok = False
|
|
|
- color = 'blue'
|
|
|
-
|
|
|
- name = ImmutableAttr(str)
|
|
|
- pubkey_type = ImmutableAttr(str)
|
|
|
- compressed = ImmutableAttr(bool,set_none_ok=True)
|
|
|
- gen_method = ImmutableAttr(str,set_none_ok=True)
|
|
|
- addr_fmt = ImmutableAttr(str,set_none_ok=True)
|
|
|
- wif_label = ImmutableAttr(str,set_none_ok=True)
|
|
|
- extra_attrs = ImmutableAttr(tuple,set_none_ok=True)
|
|
|
- desc = ImmutableAttr(str)
|
|
|
-
|
|
|
- mmtypes = {
|
|
|
- 'L': ati('legacy', 'std', False,'p2pkh', 'p2pkh', 'wif', (), 'Legacy uncompressed address'),
|
|
|
- 'C': ati('compressed','std', True, 'p2pkh', 'p2pkh', 'wif', (), 'Compressed P2PKH address'),
|
|
|
- 'S': ati('segwit', 'std', True, 'segwit', 'p2sh', 'wif', (), 'Segwit P2SH-P2WPKH address'),
|
|
|
- 'B': ati('bech32', 'std', True, 'bech32', 'bech32', 'wif', (), 'Native Segwit (Bech32) address'),
|
|
|
- 'E': ati('ethereum', 'std', False,'ethereum','ethereum','privkey', ('wallet_passwd',),'Ethereum address'),
|
|
|
- 'Z': ati('zcash_z','zcash_z',False,'zcash_z', 'zcash_z', 'wif', ('viewkey',), 'Zcash z-address'),
|
|
|
- 'M': ati('monero', 'monero', False,'monero', 'monero', 'spendkey',('viewkey','wallet_passwd'),'Monero address'),
|
|
|
- }
|
|
|
- def __new__(cls,proto,id_str,errmsg=None):
|
|
|
- if isinstance(id_str,cls):
|
|
|
- return id_str
|
|
|
- try:
|
|
|
- for k,v in cls.mmtypes.items():
|
|
|
- if id_str in (k,v.name):
|
|
|
- if id_str == v.name:
|
|
|
- id_str = k
|
|
|
- me = str.__new__(cls,id_str)
|
|
|
- for k in v._fields:
|
|
|
- setattr(me,k,getattr(v,k))
|
|
|
- if me not in proto.mmtypes + ('P',):
|
|
|
- raise ValueError(f'{me.name!r}: invalid address type for {proto.name} protocol')
|
|
|
- me.proto = proto
|
|
|
- return me
|
|
|
- raise ValueError(f'{id_str}: unrecognized address type for protocol {proto.name}')
|
|
|
- except Exception as e:
|
|
|
- return cls.init_fail( e,
|
|
|
- f"{errmsg or ''}{id_str!r}: invalid value for {cls.__name__} ({e!s})",
|
|
|
- preformat = True )
|
|
|
-
|
|
|
- @classmethod
|
|
|
- def get_names(cls):
|
|
|
- return [v.name for v in cls.mmtypes.values()]
|
|
|
-
|
|
|
-class MMGenPasswordType(MMGenAddrType):
|
|
|
- mmtypes = {
|
|
|
- 'P': ati('password', 'password', None, None, None, None, None, 'Password generated from MMGen seed')
|
|
|
- }
|