@ -1204,68 +1204,58 @@ class Deterministic_Wallet(Abstract_Wallet):
if not self . accounts :
return ' create_accounts '
def get_master_public_keys ( self ) :
out = { }
for k , account in self . accounts . items ( ) :
name = self . get_account_name ( k )
mpk_text = ' \n \n ' . join ( account . get_master_pubkeys ( ) )
out [ name ] = mpk_text
return out
class BIP32_Wallet ( Deterministic_Wallet ) :
# bip32 derivation
# Wallet with a single BIP32 account, no seed
# gap limit 20
def __init__ ( self , storage ) :
Deterministic_Wallet . __init__ ( self , storage )
self . master_public_keys = storage . get ( ' master_public_keys ' , { } )
self . master_private_keys = storage . get ( ' master_private_keys ' , { } )
self . gap_limit = 20
def default_account ( self ) :
return self . accounts [ " m/0 ' " ]
return self . accounts [ ' 0 ' ]
def is_watching_only ( self ) :
return not bool ( self . master_private_keys )
def can_create_accounts ( self ) :
return ' m/ ' in self . master_private_keys . keys ( )
def get_master_public_key ( self ) :
return self . master_public_keys . get ( " m/ " )
def get_master_public_keys ( self ) :
out = { }
for k , account in self . accounts . items ( ) :
name = self . get_account_name ( k )
mpk_text = ' \n \n ' . join ( account . get_master_pubkeys ( ) )
out [ name ] = mpk_text
return out
return self . master_public_keys . get ( self . root_name )
def get_master_private_key ( self , account , password ) :
k = self . master_private_keys . get ( account )
if not k : return
xpri v = pw_decode ( k , password )
return xpri v
xprv = pw_decode ( k , password )
return xprv
def check_password ( self , password ) :
xpriv = self . get_master_private_key ( " m/ " , password )
xpub = self . master_public_keys [ " m/ " ]
xpriv = self . get_master_private_key ( self . root_name , password )
xpub = self . master_public_keys [ self . root_name ]
assert deserialize_xkey ( xpriv ) [ 3 ] == deserialize_xkey ( xpub ) [ 3 ]
def create_xprv_wallet ( self , xprv , password ) :
xpub = bitcoin . xpub_from_xprv ( xprv )
account = BIP32_Account ( { ' xpub ' : xpub } )
account_id = ' m/ ' + bitcoin . get_xkey_name ( xpub )
self . storage . put ( ' seed_version ' , self . seed_version , True )
self . add_master_private_key ( account_id , xprv , password )
self . add_master_public_key ( account_id , xpub )
self . add_account ( account_id , account )
self . add_master_private_key ( self . root_name , xprv , password )
self . add_master_public_key ( self . root_name , xpub )
self . add_account ( ' 0 ' , account )
def create_xpub_wallet ( self , xpub ) :
account = BIP32_Account ( { ' xpub ' : xpub } )
account_id = ' m/ ' + bitcoin . get_xkey_name ( xpub )
self . storage . put ( ' seed_version ' , self . seed_version , True )
self . add_master_public_key ( account_id , xpub )
self . add_account ( account_id , account )
def create_accounts ( self , password ) :
# First check the password is valid (this raises if it isn't).
if not self . is_watching_only ( ) :
self . check_password ( password )
self . create_account ( ' Main account ' , password )
self . add_master_public_key ( self . root_name , xpub )
self . add_account ( ' 0 ' , account )
def add_master_public_key ( self , name , xpub ) :
self . master_public_keys [ name ] = xpub
@ -1275,6 +1265,19 @@ class BIP32_Wallet(Deterministic_Wallet):
self . master_private_keys [ name ] = pw_encode ( xpriv , password )
self . storage . put ( ' master_private_keys ' , self . master_private_keys , True )
def add_master_keys ( self , root , derivation , password ) :
x = self . master_private_keys . get ( root )
if x :
master_xpriv = pw_decode ( x , password )
xpriv , xpub = bip32_private_derivation ( master_xpriv , root , derivation )
self . add_master_public_key ( derivation , xpub )
self . add_master_private_key ( derivation , xpriv , password )
else :
master_xpub = self . master_public_keys [ root ]
xpub = bip32_public_derivation ( master_xpub , root , derivation )
self . add_master_public_key ( derivation , xpub )
return xpub
def can_sign ( self , tx ) :
if self . is_watching_only ( ) :
return False
@ -1292,11 +1295,19 @@ class BIP32_Wallet(Deterministic_Wallet):
class BIP32_HD_Wallet ( BIP32_Wallet ) :
# sequence of accounts
# wallet that can create accounts
def create_main_account ( self , password ) :
# First check the password is valid (this raises if it isn't).
if not self . is_watching_only ( ) :
self . check_password ( password )
self . create_account ( ' Main account ' , password )
def can_create_accounts ( self ) :
return self . root_name in self . master_private_keys . keys ( )
def create_account ( self , name , password ) :
i = self . num_accounts ( )
account_id = self . account_id ( i )
account_id = " %d " % self . num_accounts ( )
account = self . make_account ( account_id , password )
self . add_account ( account_id , account )
if name :
@ -1328,8 +1339,7 @@ class BIP32_HD_Wallet(BIP32_Wallet):
self . next_addresses . pop ( account_id )
def next_account_address ( self , password ) :
i = self . num_accounts ( )
account_id = self . account_id ( i )
account_id = ' %d ' % self . num_accounts ( )
addr = self . next_addresses . get ( account_id )
if not addr :
account = self . make_account ( account_id , password )
@ -1338,12 +1348,10 @@ class BIP32_HD_Wallet(BIP32_Wallet):
self . storage . put ( ' next_addresses ' , self . next_addresses )
return account_id , addr
def account_id ( self , i ) :
return " m/ %d ' " % i
def make_account ( self , account_id , password ) :
""" Creates and saves the master keys, but does not save the account """
xpub = self . add_master_keys ( " m/ " , account_id , password )
derivation = self . root_name + " %d ' " % int ( account_id )
xpub = self . add_master_keys ( self . root_name , derivation , password )
account = BIP32_Account ( { ' xpub ' : xpub } )
return account
@ -1355,29 +1363,23 @@ class BIP32_HD_Wallet(BIP32_Wallet):
keys . append ( k )
i = 0
while True :
account_id = self . account_id ( i )
if account_id not in keys : break
account_id = ' %d ' % i
if account_id not in keys :
break
i + = 1
return i
def add_master_keys ( self , root , account_id , password ) :
x = self . master_private_keys . get ( root )
if x :
master_xpriv = pw_decode ( x , password )
xpriv , xpub = bip32_private_derivation ( master_xpriv , root , account_id )
self . add_master_public_key ( account_id , xpub )
self . add_master_private_key ( account_id , xpriv , password )
else :
master_xpub = self . master_public_keys [ root ]
xpub = bip32_public_derivation ( master_xpub , root , account_id )
self . add_master_public_key ( account_id , xpub )
return xpub
class New Wallet( BIP32_HD _Wallet ) :
class BIP39_Wallet ( BIP32_Wallet ) :
# BIP39 seed generation
def create_master_keys ( self , password ) :
seed = self . get_seed ( password )
xprv , xpub = bip32_root ( seed )
xprv , xpub = bip32_private_derivation ( xprv , " m/ " , self . root_derivation )
self . add_master_public_key ( self . root_name , xpub )
self . add_master_private_key ( self . root_name , xprv , password )
@classmethod
def make_seed ( self , custom_entropy = 1 ) :
import mnemonic
@ -1405,45 +1407,41 @@ class NewWallet(BIP32_HD_Wallet):
import unicodedata
return NEW_SEED_VERSION , unicodedata . normalize ( ' NFC ' , unicode ( seed . strip ( ) ) )
def create_master_keys ( self , password ) :
seed = self . get_seed ( password )
xpriv , xpub = bip32_root ( seed )
self . add_master_public_key ( " m/ " , xpub )
self . add_master_private_key ( " m/ " , xpriv , password )
class NewWallet ( BIP32_HD_Wallet , BIP39_Wallet ) :
# bip 44
root_name = ' root/ '
root_derivation = " m/44 ' /0 ' "
class Wallet_2of2 ( NewWallet ) :
""" This class is used for multisignature addresses """
class Wallet_2of2 ( BIP39_Wallet ) :
# Wallet with multisig addresses.
# Cannot create accounts
root_name = " x1/ "
root_derivation = " m/44 ' /0 ' "
def __init__ ( self , storage ) :
NewWallet . __init__ ( self , storage )
BIP39_ Wallet. __init__ ( self , storage )
self . storage . put ( ' wallet_type ' , ' 2of2 ' , True )
def default_account ( self ) :
return self . accounts [ ' m/ ' ]
def can_create_accounts ( self ) :
return False
def can_import ( self ) :
return False
def create_account ( self , name , password ) :
xpub1 = self . master_public_keys . get ( " m /" )
xpub2 = self . master_public_keys . get ( " cold /" )
def create_main_account ( self , password ) :
xpub1 = self . master_public_keys . get ( " x1/ " )
xpub2 = self . master_public_keys . get ( " x2/ " )
account = BIP32_Account_2of2 ( { ' xpub ' : xpub1 , ' xpub2 ' : xpub2 } )
self . add_account ( ' m/ ' , account )
self . add_account ( ' 0 ' , account )
def get_master_public_keys ( self ) :
xpub1 = self . master_public_keys . get ( " m /" )
xpub2 = self . master_public_keys . get ( " cold /" )
return { ' hot ' : xpub1 , ' cold ' : xpub2 }
xpub1 = self . master_public_keys . get ( " x1 /" )
xpub2 = self . master_public_keys . get ( " x2 /" )
return { ' x1 ' : xpub1 , ' x2 ' : xpub2 }
def get_action ( self ) :
xpub1 = self . master_public_keys . get ( " m /" )
xpub2 = self . master_public_keys . get ( " cold /" )
xpub1 = self . master_public_keys . get ( " x1 /" )
xpub2 = self . master_public_keys . get ( " x2 /" )
if xpub1 is None :
return ' create_seed '
if xpub2 is None :
@ -1459,23 +1457,23 @@ class Wallet_2of3(Wallet_2of2):
Wallet_2of2 . __init__ ( self , storage )
self . storage . put ( ' wallet_type ' , ' 2of3 ' , True )
def create_account ( self , name , password ) :
xpub1 = self . master_public_keys . get ( " m /" )
xpub2 = self . master_public_keys . get ( " cold /" )
xpub3 = self . master_public_keys . get ( " remote /" )
def create_main_ account ( self , password ) :
xpub1 = self . master_public_keys . get ( " x1 /" )
xpub2 = self . master_public_keys . get ( " x2 /" )
xpub3 = self . master_public_keys . get ( " x3 /" )
account = BIP32_Account_2of3 ( { ' xpub ' : xpub1 , ' xpub2 ' : xpub2 , ' xpub3 ' : xpub3 } )
self . add_account ( ' m/ ' , account )
self . add_account ( ' 0 ' , account )
def get_master_public_keys ( self ) :
xpub1 = self . master_public_keys . get ( " m /" )
xpub2 = self . master_public_keys . get ( " cold /" )
xpub3 = self . master_public_keys . get ( " remote /" )
return { ' hot ' : xpub1 , ' cold ' : xpub2 , ' remote ' : xpub3 }
xpub1 = self . master_public_keys . get ( " x1 /" )
xpub2 = self . master_public_keys . get ( " x2 /" )
xpub3 = self . master_public_keys . get ( " x3 /" )
return { ' x1 ' : xpub1 , ' x2 ' : xpub2 , ' x3 ' : xpub3 }
def get_action ( self ) :
xpub1 = self . master_public_keys . get ( " m /" )
xpub2 = self . master_public_keys . get ( " cold /" )
xpub3 = self . master_public_keys . get ( " remote /" )
xpub1 = self . master_public_keys . get ( " x1 /" )
xpub2 = self . master_public_keys . get ( " x2 /" )
xpub3 = self . master_public_keys . get ( " x3 /" )
if xpub1 is None :
return ' create_seed '
if xpub2 is None or xpub3 is None :
@ -1523,7 +1521,7 @@ class OldWallet(Deterministic_Wallet):
def get_master_public_keys ( self ) :
return { ' Main Account ' : self . get_master_public_key ( ) }
def create_accounts ( self , password ) :
def create_main_ account ( self , password ) :
mpk = self . storage . get ( " master_public_key " )
self . create_account ( mpk )
@ -1574,7 +1572,7 @@ class Wallet(object):
config = storage . config
self . wallet_types = [
#('standard', ("Standard wallet"), NewWallet if config.get('bip32') else OldWallet) ,
( ' standard ' , ( " Standard wallet " ) , NewWallet ) ,
( ' imported ' , ( " Imported wallet " ) , Imported_Wallet ) ,
( ' 2of2 ' , ( " Multisig wallet (2 of 2) " ) , Wallet_2of2 ) ,
( ' 2of3 ' , ( " Multisig wallet (2 of 3) " ) , Wallet_2of3 )
@ -1586,7 +1584,7 @@ class Wallet(object):
return WalletClass ( storage )
if not storage . file_exists :
seed_version = NEW_SEED_VERSION if config . get ( ' bip32 ' ) is True else OLD_SEED_VERSION
seed_version = NEW_SEED_VERSION
else :
seed_version = storage . get ( ' seed_version ' )
if not seed_version :