2016-06-16 10:25:44 -07:00
#!/usr/bin/env python
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2016 Thomas Voegtlin
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
2017-01-22 10:25:24 -08:00
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
2016-06-16 10:25:44 -07:00
2017-01-22 10:25:24 -08:00
import six
2016-06-16 10:25:44 -07:00
import os
2017-01-22 10:25:24 -08:00
from . import bitcoin
from . import keystore
from . keystore import bip44_derivation
from . wallet import Wallet , Imported_Wallet , Standard_Wallet , Multisig_Wallet , wallet_types
from . i18n import _
from . plugins import run_hook
2016-07-01 02:44:26 -07:00
2016-06-16 10:25:44 -07:00
class BaseWizard ( object ) :
2017-03-05 04:30:57 -08:00
def __init__ ( self , config , storage ) :
2016-06-16 10:25:44 -07:00
super ( BaseWizard , self ) . __init__ ( )
2016-07-01 23:58:56 -07:00
self . config = config
2017-03-05 04:30:57 -08:00
self . storage = storage
2016-06-16 10:25:44 -07:00
self . wallet = None
2016-06-20 07:25:11 -07:00
self . stack = [ ]
2016-07-01 23:58:56 -07:00
self . plugin = None
2016-08-24 00:13:21 -07:00
self . keystores = [ ]
2016-08-29 06:33:16 -07:00
self . is_kivy = config . get ( ' gui ' ) == ' kivy '
2017-01-16 00:48:38 -08:00
self . seed_type = None
2016-06-16 10:25:44 -07:00
2016-07-30 06:04:15 -07:00
def run ( self , * args ) :
action = args [ 0 ]
args = args [ 1 : ]
2016-06-20 07:25:11 -07:00
self . stack . append ( ( action , args ) )
2016-06-16 10:25:44 -07:00
if not action :
return
2016-07-01 23:58:56 -07:00
if type ( action ) is tuple :
self . plugin , action = action
if self . plugin and hasattr ( self . plugin , action ) :
f = getattr ( self . plugin , action )
2017-07-31 20:22:18 -07:00
f ( self , * args )
2016-06-20 07:25:11 -07:00
elif hasattr ( self , action ) :
2016-06-16 10:25:44 -07:00
f = getattr ( self , action )
2017-07-31 20:22:18 -07:00
f ( * args )
2016-06-16 10:25:44 -07:00
else :
raise BaseException ( " unknown action " , action )
2016-06-20 07:25:11 -07:00
def can_go_back ( self ) :
return len ( self . stack ) > 1
def go_back ( self ) :
if not self . can_go_back ( ) :
return
self . stack . pop ( )
action , args = self . stack . pop ( )
self . run ( action , * args )
2016-06-16 10:25:44 -07:00
def new ( self ) :
name = os . path . basename ( self . storage . path )
2017-07-14 03:53:35 -07:00
title = _ ( " Create " ) + ' ' + name . decode ( ' utf8 ' )
2016-06-20 07:25:11 -07:00
message = ' \n ' . join ( [
2016-06-16 10:25:44 -07:00
_ ( " What kind of wallet do you want to create? " )
] )
2016-06-20 07:25:11 -07:00
wallet_kinds = [
( ' standard ' , _ ( " Standard wallet " ) ) ,
2016-08-19 08:26:57 -07:00
( ' 2fa ' , _ ( " Wallet with two-factor authentication " ) ) ,
2016-06-20 07:25:11 -07:00
( ' multisig ' , _ ( " Multi-signature wallet " ) ) ,
2016-08-22 03:50:24 -07:00
( ' imported ' , _ ( " Watch Bitcoin addresses " ) ) ,
2016-06-16 10:25:44 -07:00
]
2016-08-19 08:26:57 -07:00
choices = [ pair for pair in wallet_kinds if pair [ 0 ] in wallet_types ]
2016-07-01 23:58:56 -07:00
self . choice_dialog ( title = title , message = message , choices = choices , run_next = self . on_wallet_type )
2016-06-20 07:25:11 -07:00
2016-09-27 21:30:00 -07:00
def load_2fa ( self ) :
self . storage . put ( ' wallet_type ' , ' 2fa ' )
self . storage . put ( ' use_trustedcoin ' , True )
self . plugin = self . plugins . load_plugin ( ' trustedcoin ' )
2016-06-20 07:25:11 -07:00
def on_wallet_type ( self , choice ) :
self . wallet_type = choice
if choice == ' standard ' :
2016-08-19 02:47:07 -07:00
action = ' choose_keystore '
2016-06-20 07:25:11 -07:00
elif choice == ' multisig ' :
action = ' choose_multisig '
2016-08-19 08:26:57 -07:00
elif choice == ' 2fa ' :
2016-09-27 21:30:00 -07:00
self . load_2fa ( )
2016-07-01 23:58:56 -07:00
action = self . storage . get_action ( )
2016-08-22 03:50:24 -07:00
elif choice == ' imported ' :
action = ' import_addresses '
2016-06-20 07:25:11 -07:00
self . run ( action )
def choose_multisig ( self ) :
def on_multisig ( m , n ) :
self . multisig_type = " %d of %d " % ( m , n )
2016-08-22 03:50:24 -07:00
self . storage . put ( ' wallet_type ' , self . multisig_type )
2016-07-01 23:58:56 -07:00
self . n = n
2016-08-19 02:47:07 -07:00
self . run ( ' choose_keystore ' )
2016-06-20 07:25:11 -07:00
self . multisig_dialog ( run_next = on_multisig )
2016-06-16 10:25:44 -07:00
2016-08-19 02:47:07 -07:00
def choose_keystore ( self ) :
2016-08-19 05:45:52 -07:00
assert self . wallet_type in [ ' standard ' , ' multisig ' ]
2016-08-24 00:13:21 -07:00
i = len ( self . keystores )
title = _ ( ' Add cosigner ' ) + ' ( %d of %d ) ' % ( i + 1 , self . n ) if self . wallet_type == ' multisig ' else _ ( ' Keystore ' )
if self . wallet_type == ' standard ' or i == 0 :
message = _ ( ' Do you want to create a new seed, or to restore a wallet using an existing seed? ' )
2016-08-22 03:50:24 -07:00
choices = [
( ' create_seed ' , _ ( ' Create a new seed ' ) ) ,
2016-08-24 21:43:27 -07:00
( ' restore_from_seed ' , _ ( ' I already have a seed ' ) ) ,
2016-08-28 02:29:16 -07:00
( ' restore_from_key ' , _ ( ' Use public or private keys ' ) ) ,
2016-08-22 03:50:24 -07:00
]
2016-08-30 02:19:30 -07:00
if not self . is_kivy :
choices . append ( ( ' choose_hw_device ' , _ ( ' Use a hardware device ' ) ) )
2016-08-22 03:50:24 -07:00
else :
2016-08-24 00:13:21 -07:00
message = _ ( ' Add a cosigner to your multi-sig wallet ' )
2016-08-22 03:50:24 -07:00
choices = [
2016-08-28 02:29:16 -07:00
( ' restore_from_key ' , _ ( ' Enter cosigner key ' ) ) ,
2016-09-28 08:03:02 -07:00
( ' restore_from_seed ' , _ ( ' Enter cosigner seed ' ) ) ,
2016-08-22 03:50:24 -07:00
]
2016-08-30 02:19:30 -07:00
if not self . is_kivy :
choices . append ( ( ' choose_hw_device ' , _ ( ' Cosign with hardware device ' ) ) )
2016-08-22 03:50:24 -07:00
2016-08-19 05:45:52 -07:00
self . choice_dialog ( title = title , message = message , choices = choices , run_next = self . run )
2016-06-16 10:25:44 -07:00
2016-08-22 03:50:24 -07:00
def import_addresses ( self ) :
v = keystore . is_address_list
title = _ ( " Import Bitcoin Addresses " )
message = _ ( " Enter a list of Bitcoin addresses. This will create a watching-only wallet. " )
2016-09-28 12:31:47 -07:00
self . add_xpub_dialog ( title = title , message = message , run_next = self . on_import_addresses , is_valid = v )
2016-08-24 21:43:27 -07:00
def on_import_addresses ( self , text ) :
assert keystore . is_address_list ( text )
self . wallet = Imported_Wallet ( self . storage )
for x in text . split ( ) :
self . wallet . import_address ( x )
self . terminate ( )
2016-08-22 03:50:24 -07:00
2016-07-01 02:44:26 -07:00
def restore_from_key ( self ) :
if self . wallet_type == ' standard ' :
2016-07-01 23:58:56 -07:00
v = keystore . is_any_key
2016-08-28 02:29:16 -07:00
title = _ ( " Create keystore from keys " )
2016-07-01 02:44:26 -07:00
message = ' ' . join ( [
2016-08-22 03:50:24 -07:00
_ ( " To create a watching-only wallet, please enter your master public key (xpub). " ) ,
2016-07-01 02:44:26 -07:00
_ ( " To create a spending wallet, please enter a master private key (xprv), or a list of Bitcoin private keys. " )
] )
2016-09-26 03:02:54 -07:00
self . add_xpub_dialog ( title = title , message = message , run_next = self . on_restore_from_key , is_valid = v )
2016-07-01 02:44:26 -07:00
else :
2016-07-01 23:58:56 -07:00
v = keystore . is_bip32_key
2016-09-26 03:02:54 -07:00
i = len ( self . keystores ) + 1
self . add_cosigner_dialog ( index = i , run_next = self . on_restore_from_key , is_valid = v )
2016-08-24 21:43:27 -07:00
def on_restore_from_key ( self , text ) :
2016-08-25 03:18:51 -07:00
k = keystore . from_keys ( text )
self . on_keystore ( k )
2016-06-20 07:25:11 -07:00
2016-08-24 00:13:21 -07:00
def choose_hw_device ( self ) :
2016-08-19 02:47:07 -07:00
title = _ ( ' Hardware Keystore ' )
2016-08-23 04:40:11 -07:00
# check available plugins
support = self . plugins . get_hardware_support ( )
if not support :
msg = ' \n ' . join ( [
2016-06-20 07:25:11 -07:00
_ ( ' No hardware wallet support found on your system. ' ) ,
_ ( ' Please install the relevant libraries (eg python-trezor for Trezor). ' ) ,
] )
2016-08-24 00:13:21 -07:00
self . confirm_dialog ( title = title , message = msg , run_next = lambda x : self . choose_hw_device ( ) )
2016-08-23 04:40:11 -07:00
return
# scan devices
devices = [ ]
2016-08-23 20:58:41 -07:00
devmgr = self . plugins . device_manager
2016-08-23 04:40:11 -07:00
for name , description , plugin in support :
try :
2016-08-23 20:58:41 -07:00
# FIXME: side-effect: unpaired_device_info sets client.handler
u = devmgr . unpaired_device_infos ( None , plugin )
2016-08-23 04:40:11 -07:00
except :
2016-08-23 20:58:41 -07:00
devmgr . print_error ( " error " , name )
2016-08-23 04:40:11 -07:00
continue
devices + = map ( lambda x : ( name , x ) , u )
if not devices :
2017-03-21 02:07:31 -07:00
msg = ' ' . join ( [
_ ( ' No hardware device detected. ' ) + ' \n ' ,
_ ( ' To trigger a rescan, press \' Next \' . ' ) + ' \n \n ' ,
_ ( ' If your device is not detected on Windows, go to " Settings " , " Devices " , " Connected devices " , and do " Remove device " . Then, plug your device again. ' ) + ' ' ,
_ ( ' On Linux, you might have to add a new permission to your udev rules. ' ) ,
2016-08-23 04:40:11 -07:00
] )
2016-08-24 00:13:21 -07:00
self . confirm_dialog ( title = title , message = msg , run_next = lambda x : self . choose_hw_device ( ) )
2016-08-23 04:40:11 -07:00
return
# select device
self . devices = devices
choices = [ ]
2016-08-25 06:31:21 -07:00
for name , info in devices :
state = _ ( " initialized " ) if info . initialized else _ ( " wiped " )
label = info . label or _ ( " An unnamed %s " ) % name
descr = " %s [ %s , %s ] " % ( label , name , state )
choices . append ( ( ( name , info ) , descr ) )
2016-08-23 04:40:11 -07:00
msg = _ ( ' Select a device ' ) + ' : '
self . choice_dialog ( title = title , message = msg , choices = choices , run_next = self . on_device )
def on_device ( self , name , device_info ) :
2016-08-24 01:47:27 -07:00
self . plugin = self . plugins . get_plugin ( name )
2016-10-19 23:32:44 -07:00
try :
self . plugin . setup_device ( device_info , self )
except BaseException as e :
self . show_error ( str ( e ) )
self . choose_hw_device ( )
return
2016-09-23 10:00:42 -07:00
if self . wallet_type == ' multisig ' :
# There is no general standard for HD multisig.
# This is partially compatible with BIP45; assumes index=0
self . on_hw_derivation ( name , device_info , " m/45 ' /0 " )
else :
2017-06-20 01:47:02 -07:00
f = lambda x : self . run ( ' on_hw_derivation ' , name , device_info , str ( x ) )
self . derivation_dialog ( f )
2016-08-30 00:51:53 -07:00
2017-06-20 01:47:02 -07:00
def derivation_dialog ( self , f ) :
default = bip44_derivation ( 0 )
2016-08-30 00:51:53 -07:00
message = ' \n ' . join ( [
2017-06-20 01:47:02 -07:00
_ ( ' Enter your wallet derivation here. ' ) ,
_ ( ' If you are not sure what this is, leave this field unchanged. ' )
2016-08-30 00:51:53 -07:00
] )
2017-06-20 01:47:02 -07:00
self . line_dialog ( run_next = f , title = _ ( ' Derivation ' ) , message = message , default = default , test = bitcoin . is_bip32_derivation )
2016-08-15 02:48:33 -07:00
2016-09-23 10:00:42 -07:00
def on_hw_derivation ( self , name , device_info , derivation ) :
from keystore import hardware_keystore
2016-08-24 01:47:27 -07:00
xpub = self . plugin . get_xpub ( device_info . device . id_ , derivation , self )
2016-08-28 23:47:48 -07:00
if xpub is None :
self . show_error ( ' Cannot read xpub from device ' )
return
2016-08-23 00:21:24 -07:00
d = {
' type ' : ' hardware ' ,
2016-08-23 23:52:21 -07:00
' hw_type ' : name ,
2016-08-23 00:21:24 -07:00
' derivation ' : derivation ,
' xpub ' : xpub ,
2016-08-26 02:45:12 -07:00
' label ' : device_info . label ,
2016-08-23 00:21:24 -07:00
}
2016-08-31 00:35:27 -07:00
k = hardware_keystore ( d )
2016-08-25 03:42:00 -07:00
self . on_keystore ( k )
2016-07-01 23:58:56 -07:00
2016-09-27 21:30:00 -07:00
def passphrase_dialog ( self , run_next ) :
2016-10-10 08:11:46 -07:00
title = _ ( ' Seed extension ' )
2016-09-27 21:30:00 -07:00
message = ' \n ' . join ( [
2016-10-10 08:11:46 -07:00
_ ( ' You may extend your seed with custom words. ' ) ,
_ ( ' Your seed extension must be saved together with your seed. ' ) ,
2016-09-27 21:30:00 -07:00
] )
warning = ' \n ' . join ( [
_ ( ' Note that this is NOT your encryption password. ' ) ,
_ ( ' If you do not know what this is, leave this field empty. ' ) ,
] )
2016-10-10 08:11:46 -07:00
self . line_dialog ( title = title , message = message , warning = warning , default = ' ' , test = lambda x : True , run_next = run_next )
2016-08-30 00:51:53 -07:00
2016-09-27 21:30:00 -07:00
def restore_from_seed ( self ) :
2016-09-28 00:53:17 -07:00
self . opt_bip39 = True
2016-09-29 16:15:28 -07:00
self . opt_ext = True
2016-09-28 00:55:18 -07:00
test = bitcoin . is_seed if self . wallet_type == ' standard ' else bitcoin . is_new_seed
2016-09-27 21:30:00 -07:00
self . restore_seed_dialog ( run_next = self . on_restore_seed , test = test )
2016-08-15 02:48:33 -07:00
2016-09-29 16:15:28 -07:00
def on_restore_seed ( self , seed , is_bip39 , is_ext ) :
2017-01-16 00:48:38 -08:00
self . seed_type = ' bip39 ' if is_bip39 else bitcoin . seed_type ( seed )
if self . seed_type == ' bip39 ' :
2016-09-29 16:15:28 -07:00
f = lambda passphrase : self . on_restore_bip39 ( seed , passphrase )
self . passphrase_dialog ( run_next = f ) if is_ext else f ( ' ' )
2017-01-16 00:48:38 -08:00
elif self . seed_type in [ ' standard ' , ' segwit ' ] :
f = lambda passphrase : self . run ( ' create_keystore ' , seed , passphrase )
self . passphrase_dialog ( run_next = f ) if is_ext else f ( ' ' )
elif self . seed_type == ' old ' :
self . run ( ' create_keystore ' , seed , ' ' )
elif self . seed_type == ' 2fa ' :
if self . is_kivy :
self . show_error ( ' 2FA seeds are not supported in this version ' )
self . run ( ' restore_from_seed ' )
2016-09-27 21:30:00 -07:00
else :
2017-01-16 00:48:38 -08:00
self . load_2fa ( )
self . run ( ' on_restore_seed ' , seed , is_ext )
else :
raise BaseException ( ' Unknown seed type ' , seed_type )
2016-09-27 21:30:00 -07:00
def on_restore_bip39 ( self , seed , passphrase ) :
2017-06-20 01:47:02 -07:00
f = lambda x : self . run ( ' on_bip44 ' , seed , passphrase , str ( x ) )
self . derivation_dialog ( f )
2016-08-15 02:48:33 -07:00
2016-08-25 03:18:51 -07:00
def create_keystore ( self , seed , passphrase ) :
2016-08-30 00:51:53 -07:00
k = keystore . from_seed ( seed , passphrase )
self . on_keystore ( k )
2016-08-24 21:43:27 -07:00
2017-06-20 01:47:02 -07:00
def on_bip44 ( self , seed , passphrase , derivation ) :
2016-08-25 00:48:11 -07:00
k = keystore . BIP32_KeyStore ( { } )
2016-08-15 02:48:33 -07:00
bip32_seed = keystore . bip39_to_seed ( seed , passphrase )
2017-02-22 23:44:56 -08:00
k . add_xprv_from_seed ( bip32_seed , 0 , derivation )
2016-08-25 03:18:51 -07:00
self . on_keystore ( k )
2016-07-01 23:58:56 -07:00
2016-08-25 03:18:51 -07:00
def on_keystore ( self , k ) :
2016-06-16 10:25:44 -07:00
if self . wallet_type == ' standard ' :
2016-08-25 03:18:51 -07:00
self . keystores . append ( k )
self . run ( ' create_wallet ' )
2016-06-20 07:25:11 -07:00
elif self . wallet_type == ' multisig ' :
2016-08-22 03:50:24 -07:00
if k . xpub in map ( lambda x : x . xpub , self . keystores ) :
2016-08-30 02:19:30 -07:00
self . show_error ( _ ( ' Error: duplicate master public key ' ) )
self . run ( ' choose_keystore ' )
return
2016-08-22 03:50:24 -07:00
self . keystores . append ( k )
if len ( self . keystores ) == 1 :
xpub = k . get_master_public_key ( )
self . stack = [ ]
self . run ( ' show_xpub_and_add_cosigners ' , xpub )
elif len ( self . keystores ) < self . n :
self . run ( ' choose_keystore ' )
else :
2016-08-25 03:18:51 -07:00
self . run ( ' create_wallet ' )
def create_wallet ( self ) :
if any ( k . may_have_password ( ) for k in self . keystores ) :
self . request_password ( run_next = self . on_password )
else :
2017-03-01 23:19:51 -08:00
self . on_password ( None , False )
2016-08-25 03:18:51 -07:00
2017-02-09 08:08:27 -08:00
def on_password ( self , password , encrypt ) :
self . storage . set_password ( password , encrypt )
2016-08-25 03:18:51 -07:00
for k in self . keystores :
if k . may_have_password ( ) :
k . update_password ( None , password )
if self . wallet_type == ' standard ' :
2017-01-16 00:48:38 -08:00
self . storage . put ( ' seed_type ' , self . seed_type )
2016-08-25 03:18:51 -07:00
self . storage . put ( ' keystore ' , k . dump ( ) )
2017-01-25 12:41:26 -08:00
self . wallet = Standard_Wallet ( self . storage )
2016-08-25 03:18:51 -07:00
self . run ( ' create_addresses ' )
elif self . wallet_type == ' multisig ' :
for i , k in enumerate ( self . keystores ) :
self . storage . put ( ' x %d / ' % ( i + 1 ) , k . dump ( ) )
self . storage . write ( )
self . wallet = Multisig_Wallet ( self . storage )
self . run ( ' create_addresses ' )
2016-08-22 03:50:24 -07:00
def show_xpub_and_add_cosigners ( self , xpub ) :
self . show_xpub_dialog ( xpub = xpub , run_next = lambda x : self . run ( ' choose_keystore ' ) )
2016-07-01 02:44:26 -07:00
2016-07-01 23:58:56 -07:00
def add_cosigners ( self , password , i ) :
self . add_cosigner_dialog ( run_next = lambda x : self . on_cosigner ( x , password , i ) , index = i , is_valid = keystore . is_xpub )
2016-07-01 02:44:26 -07:00
2016-07-01 23:58:56 -07:00
def on_cosigner ( self , text , password , i ) :
2016-08-25 00:48:11 -07:00
k = keystore . from_keys ( text , password )
2016-08-22 03:50:24 -07:00
self . on_keystore ( k )
2016-06-16 10:25:44 -07:00
def create_seed ( self ) :
2017-01-16 00:48:38 -08:00
import mnemonic
self . seed_type = ' segwit ' if bitcoin . TESTNET and self . config . get ( ' segwit ' ) else ' standard '
seed = mnemonic . Mnemonic ( ' en ' ) . make_seed ( self . seed_type )
2016-08-28 01:33:01 -07:00
self . opt_bip39 = False
2016-09-29 16:15:28 -07:00
f = lambda x : self . request_passphrase ( seed , x )
self . show_seed_dialog ( run_next = f , seed_text = seed )
2016-08-30 00:51:53 -07:00
2016-09-29 16:15:28 -07:00
def request_passphrase ( self , seed , opt_passphrase ) :
if opt_passphrase :
f = lambda x : self . confirm_seed ( seed , x )
self . passphrase_dialog ( run_next = f )
else :
self . run ( ' confirm_seed ' , seed , ' ' )
2016-06-16 10:25:44 -07:00
2016-08-29 06:33:16 -07:00
def confirm_seed ( self , seed , passphrase ) :
2016-08-30 00:51:53 -07:00
f = lambda x : self . confirm_passphrase ( seed , passphrase )
self . confirm_seed_dialog ( run_next = f , test = lambda x : x == seed )
def confirm_passphrase ( self , seed , passphrase ) :
2016-08-30 01:36:51 -07:00
f = lambda x : self . run ( ' create_keystore ' , seed , x )
2016-08-30 00:51:53 -07:00
if passphrase :
2016-10-10 08:11:46 -07:00
title = _ ( ' Confirm Seed Extension ' )
2016-08-30 00:51:53 -07:00
message = ' \n ' . join ( [
2016-10-10 08:11:46 -07:00
_ ( ' Your seed extension must be saved together with your seed. ' ) ,
2016-08-30 00:51:53 -07:00
_ ( ' Please type it here. ' ) ,
] )
self . line_dialog ( run_next = f , title = title , message = message , default = ' ' , test = lambda x : x == passphrase )
else :
2016-08-30 01:36:51 -07:00
f ( ' ' )
2016-07-01 23:58:56 -07:00
def create_addresses ( self ) :
def task ( ) :
self . wallet . synchronize ( )
self . wallet . storage . write ( )
self . terminate ( )
msg = _ ( " Electrum is generating your addresses, please wait. " )
self . waiting_dialog ( task , msg )