commit 0fb6cdcb1a75f7f8f4c7c5b0e8fdaf67145d9326
parent 8558488337a6043bce8a246f3e7d1d471d13068d
Author: ThomasV <thomasv@gitorious>
Date: Fri, 9 May 2014 16:27:12 +0200
add 2of3 wallets in wizard
Diffstat:
2 files changed, 103 insertions(+), 39 deletions(-)
diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
@@ -97,15 +97,20 @@ class InstallWizard(QDialog):
bb2.setText(_("Wallet with two-factor authentication (plugin)"))
bb3 = QRadioButton(gb2)
- bb3.setText(_("Multisig wallet (paired manually)"))
+ bb3.setText(_("Multisig wallet (2 of 2)"))
+
+ bb4 = QRadioButton(gb2)
+ bb4.setText(_("Multisig wallet (2 of 3)"))
grid2.addWidget(bb1, 4, 0)
grid2.addWidget(bb2, 5, 0)
grid2.addWidget(bb3, 6, 0)
+ grid2.addWidget(bb4, 7, 0)
group2.addButton(bb1)
group2.addButton(bb2)
group2.addButton(bb3)
+ group2.addButton(bb4)
vbox.addLayout(grid2)
vbox.addStretch(1)
@@ -120,9 +125,11 @@ class InstallWizard(QDialog):
if bb1.isChecked():
t = 'standard'
elif bb2.isChecked():
- t = 'multisig_plugin'
+ t = '2fa'
elif bb3.isChecked():
- t = 'multisig_manual'
+ t = '2of2'
+ elif bb4.isChecked():
+ t = '2of3'
return action, t
@@ -187,6 +194,29 @@ class InstallWizard(QDialog):
return self.get_seed_text(seed_e2)
+ def cold_mpk2_dialog(self, xpub_hot):
+ vbox = QVBoxLayout()
+ vbox0, seed_e0 = seed_dialog.enter_seed_box(MSG_SHOW_MPK, 'hot')
+ seed_e0.setText(xpub_hot)
+ seed_e0.setReadOnly(True)
+ vbox1, seed_e1 = seed_dialog.enter_seed_box(MSG_ENTER_COLD_MPK, 'cold')
+ vbox2, seed_e2 = seed_dialog.enter_seed_box(MSG_ENTER_COLD_MPK, 'cold')
+ vbox.addLayout(vbox0)
+ vbox.addLayout(vbox1)
+ vbox.addLayout(vbox2)
+ vbox.addStretch(1)
+ hbox, button = ok_cancel_buttons2(self, _('Next'))
+ vbox.addLayout(hbox)
+ button.setEnabled(False)
+ f = lambda: button.setEnabled(self.is_mpk(seed_e1) and self.is_mpk(seed_e2))
+ seed_e1.textChanged.connect(f)
+ seed_e2.textChanged.connect(f)
+ self.set_layout(vbox)
+ if not self.exec_():
+ return
+ return self.get_seed_text(seed_e1), self.get_seed_text(seed_e2)
+
+
def double_seed_dialog(self):
vbox = QVBoxLayout()
vbox1, seed_e1 = seed_dialog.enter_seed_box(MSG_ENTER_SEED_OR_MPK, 'hot')
@@ -317,6 +347,30 @@ class InstallWizard(QDialog):
return run_password_dialog(self, None, self)[2]
+ def create_cold_seed(self, wallet):
+ from electrum.bitcoin import mnemonic_to_seed, bip32_root
+ msg = _('You are about to generate the cold storage seed of your wallet.') + '\n' \
+ + _('For safety, you should do this on an offline computer.')
+ icon = QPixmap( ':icons/cold_seed.png').scaledToWidth(56)
+ if not self.question(msg, icon):
+ return
+
+ cold_seed = wallet.make_seed()
+ if not self.show_seed(cold_seed, 'cold'):
+ return
+ if not self.verify_seed(cold_seed, 'cold'):
+ return
+
+ hex_seed = mnemonic_to_seed(cold_seed,'').encode('hex')
+ xpriv, xpub = bip32_root(hex_seed)
+ wallet.add_master_public_key('cold/', xpub)
+
+ msg = _('Your master public key was saved in your wallet file.') + '\n'\
+ + _('Your cold seed must be stored on paper; it is not in the wallet file.')+ '\n\n' \
+ + _('This program is about to close itself.') + '\n'\
+ + _('You will need to reopen your wallet on an online computer, in order to complete the creation of your wallet')
+ self.show_message(msg)
+
def run(self, action):
@@ -326,61 +380,66 @@ class InstallWizard(QDialog):
if action is None:
return
-
+
if action == 'create':
- if t == 'multisig_plugin':
- action = 'create_2of3_1'
- if t == 'multisig_manual':
- action = 'create_2of2_1'
-
- if action in ['create']:
- wallet = Wallet(self.storage)
- elif action in ['create_2of2_1','create_2of2_2']:
- wallet = Wallet_2of2(self.storage)
-
+ if t == 'standard':
+ wallet = Wallet(self.storage)
- if action == 'create':
- seed = wallet.make_seed()
- if not self.show_seed(seed, None):
- return
- if not self.verify_seed(seed, None):
+ elif t == '2fa':
+ wallet = Wallet_2of3(self.storage)
+ run_hook('create_cold_seed', wallet, self)
+ self.create_cold_seed(wallet)
return
- password = self.password_dialog()
- wallet.add_seed(seed, password)
- wallet.create_accounts(password)
- self.waiting_dialog(wallet.synchronize)
+ elif t == '2of2':
+ wallet = Wallet_2of2(self.storage)
+ action = 'create_2of2_1'
+
+ elif t == '2of3':
+ wallet = Wallet_2of3(self.storage)
+ action = 'create_2of3_1'
- if action == 'create_2of3_1':
- run_hook('create_cold_seed', self.storage, self)
- return
+ if action == 'create_2fa_2':
+ wallet = Wallet_2of3(self.storage)
- if action in ['create_2of2_1', 'create_2of3_2']:
+ if action in ['create', 'create_2of2_1', 'create_2fa_2', 'create_2of3_1']:
seed = wallet.make_seed()
- if not self.show_seed(seed, 'hot'):
+ sid = None if action == 'create' else 'hot'
+ if not self.show_seed(seed, sid):
return
- if not self.verify_seed(seed, 'hot'):
+ if not self.verify_seed(seed, sid):
return
password = self.password_dialog()
wallet.add_seed(seed, password)
- if action == 'create_2of2_1':
- # display mpk
+ if action == 'create':
+ wallet.create_accounts(password)
+ self.waiting_dialog(wallet.synchronize)
+ elif action == 'create_2of2_1':
action = 'create_2of2_2'
- else:
- action = 'create_2of3_3'
+ elif action == 'create_2of3_1':
+ action = 'create_2of3_2'
+ elif action == 'create_2fa_2':
+ action = 'create_2fa_3'
if action == 'create_2of2_2':
xpub_hot = wallet.master_public_keys.get("m/")
xpub = self.cold_mpk_dialog(xpub_hot)
- if not Wallet.is_mpk(xpub):
- return
wallet.add_master_public_key("cold/", xpub)
wallet.create_account()
self.waiting_dialog(wallet.synchronize)
- if action == 'create_2of3_3':
+ if action == 'create_2of3_2':
+ xpub_hot = wallet.master_public_keys.get("m/")
+ xpub1, xpub2 = self.cold_mpk2_dialog(xpub_hot)
+ wallet.add_master_public_key("cold/", xpub1)
+ wallet.add_master_public_key("remote/", xpub2)
+ wallet.create_account()
+ self.waiting_dialog(wallet.synchronize)
+
+
+ if action == 'create_2fa_3':
run_hook('create_remote_key', wallet, self)
if not wallet.master_public_keys.get("remote/"):
return
@@ -408,15 +467,17 @@ class InstallWizard(QDialog):
else:
raise
- elif t in ['multisig_plugin', 'multisig_manual']:
+ elif t in ['2fa', '2of2','2of3']:
r = self.double_seed_dialog()
if not r:
return
text1, text2 = r
password = self.password_dialog()
- if t == 'multisig_manual':
+ if t == '2of2':
wallet = Wallet_2of2(self.storage)
- else:
+ elif t == '2of3':
+ wallet = Wallet_2of3(self.storage)
+ elif t == '2fa':
wallet = Wallet_2of3(self.storage)
if Wallet.is_seed(text1):
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -1508,6 +1508,9 @@ class Wallet_2of3(Wallet_2of2):
xpub1 = self.master_public_keys.get("m/")
xpub2 = self.master_public_keys.get("cold/")
xpub3 = self.master_public_keys.get("remote/")
+ # fixme: we use order of creation
+ if xpub2 and xpub1 is None:
+ return 'create_2fa_2'
if xpub2 is None:
return 'create_2of3_1'
if xpub1 is None: