|
@ -1,10 +1,14 @@ |
|
|
|
|
|
import re |
|
|
|
|
|
import sys |
|
|
|
|
|
import threading |
|
|
|
|
|
|
|
|
from PyQt4.QtGui import * |
|
|
from PyQt4.QtGui import * |
|
|
from PyQt4.QtCore import * |
|
|
from PyQt4.QtCore import * |
|
|
import PyQt4.QtCore as QtCore |
|
|
import PyQt4.QtCore as QtCore |
|
|
|
|
|
|
|
|
import electrum |
|
|
import electrum |
|
|
from electrum.i18n import _ |
|
|
from electrum.i18n import _ |
|
|
from electrum import Wallet, Wallet_2of2, Wallet_2of3 |
|
|
from electrum import Wallet |
|
|
from electrum import bitcoin |
|
|
from electrum import bitcoin |
|
|
from electrum import util |
|
|
from electrum import util |
|
|
|
|
|
|
|
@ -13,8 +17,6 @@ from network_dialog import NetworkDialog |
|
|
from util import * |
|
|
from util import * |
|
|
from amountedit import AmountEdit |
|
|
from amountedit import AmountEdit |
|
|
|
|
|
|
|
|
import sys |
|
|
|
|
|
import threading |
|
|
|
|
|
from electrum.plugins import always_hook, run_hook |
|
|
from electrum.plugins import always_hook, run_hook |
|
|
from electrum.mnemonic import prepare_seed |
|
|
from electrum.mnemonic import prepare_seed |
|
|
|
|
|
|
|
@ -26,6 +28,42 @@ MSG_ENTER_SEED_OR_MPK = _("Please enter a wallet seed, BIP32 private key, or mas |
|
|
MSG_VERIFY_SEED = _("Your seed is important!") + "\n" + _("To make sure that you have properly saved your seed, please retype it here.") |
|
|
MSG_VERIFY_SEED = _("Your seed is important!") + "\n" + _("To make sure that you have properly saved your seed, please retype it here.") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CosignWidget(QWidget): |
|
|
|
|
|
size = 120 |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, m, n): |
|
|
|
|
|
QWidget.__init__(self) |
|
|
|
|
|
self.R = QRect(0, 0, self.size, self.size) |
|
|
|
|
|
self.setGeometry(self.R) |
|
|
|
|
|
self.m = m |
|
|
|
|
|
self.n = n |
|
|
|
|
|
|
|
|
|
|
|
def set_n(self, n): |
|
|
|
|
|
self.n = n |
|
|
|
|
|
self.update() |
|
|
|
|
|
|
|
|
|
|
|
def set_m(self, m): |
|
|
|
|
|
self.m = m |
|
|
|
|
|
self.update() |
|
|
|
|
|
|
|
|
|
|
|
def paintEvent(self, event): |
|
|
|
|
|
import math |
|
|
|
|
|
bgcolor = self.palette().color(QPalette.Background) |
|
|
|
|
|
pen = QPen(bgcolor, 7, QtCore.Qt.SolidLine) |
|
|
|
|
|
qp = QPainter() |
|
|
|
|
|
qp.begin(self) |
|
|
|
|
|
qp.setPen(pen) |
|
|
|
|
|
qp.setRenderHint(QPainter.Antialiasing) |
|
|
|
|
|
qp.setBrush(Qt.gray) |
|
|
|
|
|
for i in range(self.n): |
|
|
|
|
|
alpha = int(16* 360 * i/self.n) |
|
|
|
|
|
alpha2 = int(16* 360 * 1/self.n) |
|
|
|
|
|
qp.setBrush(Qt.green if i<self.m else Qt.gray) |
|
|
|
|
|
qp.drawPie(self.R, alpha, alpha2) |
|
|
|
|
|
qp.end() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InstallWizard(QDialog): |
|
|
class InstallWizard(QDialog): |
|
|
|
|
|
|
|
|
def __init__(self, config, network, storage, app): |
|
|
def __init__(self, config, network, storage, app): |
|
@ -36,7 +74,7 @@ class InstallWizard(QDialog): |
|
|
self.storage = storage |
|
|
self.storage = storage |
|
|
self.setMinimumSize(575, 400) |
|
|
self.setMinimumSize(575, 400) |
|
|
self.setMaximumSize(575, 400) |
|
|
self.setMaximumSize(575, 400) |
|
|
self.setWindowTitle('Electrum' + ' - ' + os.path.basename(self.storage.path)) |
|
|
self.setWindowTitle('Electrum' + ' - ' + _('Install Wizard')) |
|
|
self.connect(self, QtCore.SIGNAL('accept'), self.accept) |
|
|
self.connect(self, QtCore.SIGNAL('accept'), self.accept) |
|
|
self.stack = QStackedLayout() |
|
|
self.stack = QStackedLayout() |
|
|
self.setLayout(self.stack) |
|
|
self.setLayout(self.stack) |
|
@ -283,6 +321,48 @@ class InstallWizard(QDialog): |
|
|
return wallet_type |
|
|
return wallet_type |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def multisig_choice(self): |
|
|
|
|
|
|
|
|
|
|
|
vbox = QVBoxLayout() |
|
|
|
|
|
self.set_layout(vbox) |
|
|
|
|
|
vbox.addWidget(QLabel(_("Multi Signature Wallet"))) |
|
|
|
|
|
|
|
|
|
|
|
cw = CosignWidget(2, 2) |
|
|
|
|
|
vbox.addWidget(cw, 1) |
|
|
|
|
|
vbox.addWidget(QLabel(_("Please choose the number of signatures needed to unlock funds in your wallet") + ':')) |
|
|
|
|
|
|
|
|
|
|
|
m_edit = QSpinBox() |
|
|
|
|
|
n_edit = QSpinBox() |
|
|
|
|
|
m_edit.setValue(2) |
|
|
|
|
|
n_edit.setValue(2) |
|
|
|
|
|
n_edit.setMinimum(2) |
|
|
|
|
|
n_edit.setMaximum(15) |
|
|
|
|
|
m_edit.setMinimum(1) |
|
|
|
|
|
m_edit.setMaximum(2) |
|
|
|
|
|
n_edit.valueChanged.connect(m_edit.setMaximum) |
|
|
|
|
|
|
|
|
|
|
|
n_edit.valueChanged.connect(cw.set_n) |
|
|
|
|
|
m_edit.valueChanged.connect(cw.set_m) |
|
|
|
|
|
|
|
|
|
|
|
hbox = QHBoxLayout() |
|
|
|
|
|
hbox.addWidget(QLabel(_('Require'))) |
|
|
|
|
|
hbox.addWidget(m_edit) |
|
|
|
|
|
hbox.addWidget(QLabel(_('of'))) |
|
|
|
|
|
hbox.addWidget(n_edit) |
|
|
|
|
|
hbox.addWidget(QLabel(_('signatures'))) |
|
|
|
|
|
hbox.addStretch(1) |
|
|
|
|
|
|
|
|
|
|
|
vbox.addLayout(hbox) |
|
|
|
|
|
vbox.addStretch(1) |
|
|
|
|
|
vbox.addLayout(Buttons(CancelButton(self), OkButton(self, _('Next')))) |
|
|
|
|
|
if not self.exec_(): |
|
|
|
|
|
return |
|
|
|
|
|
m = int(m_edit.value()) |
|
|
|
|
|
n = int(n_edit.value()) |
|
|
|
|
|
wallet_type = '%dof%d'%(m,n) |
|
|
|
|
|
return wallet_type |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def question(self, msg, yes_label=_('OK'), no_label=_('Cancel'), icon=None): |
|
|
def question(self, msg, yes_label=_('OK'), no_label=_('Cancel'), icon=None): |
|
|
vbox = QVBoxLayout() |
|
|
vbox = QVBoxLayout() |
|
|
self.set_layout(vbox) |
|
|
self.set_layout(vbox) |
|
@ -319,7 +399,7 @@ class InstallWizard(QDialog): |
|
|
|
|
|
|
|
|
if action in ['create', 'restore']: |
|
|
if action in ['create', 'restore']: |
|
|
if wallet_type == 'multisig': |
|
|
if wallet_type == 'multisig': |
|
|
wallet_type = self.choice(_("Multi Signature Wallet"), 'Select wallet type', [('2of2', _("2 of 2")),('2of3',_("2 of 3"))]) |
|
|
wallet_type = self.multisig_choice() |
|
|
if not wallet_type: |
|
|
if not wallet_type: |
|
|
return |
|
|
return |
|
|
elif wallet_type == 'hardware': |
|
|
elif wallet_type == 'hardware': |
|
@ -363,22 +443,14 @@ class InstallWizard(QDialog): |
|
|
wallet.add_seed(seed, password) |
|
|
wallet.add_seed(seed, password) |
|
|
wallet.create_master_keys(password) |
|
|
wallet.create_master_keys(password) |
|
|
|
|
|
|
|
|
elif action == 'add_cosigner': |
|
|
elif action == 'add_cosigners': |
|
|
xpub1 = wallet.master_public_keys.get("x1/") |
|
|
n = int(re.match('(\d+)of(\d+)', wallet.wallet_type).group(2)) |
|
|
r = self.multi_mpk_dialog(xpub1, 1) |
|
|
|
|
|
if not r: |
|
|
|
|
|
return |
|
|
|
|
|
xpub2 = r[0] |
|
|
|
|
|
wallet.add_master_public_key("x2/", xpub2) |
|
|
|
|
|
|
|
|
|
|
|
elif action == 'add_two_cosigners': |
|
|
|
|
|
xpub1 = wallet.master_public_keys.get("x1/") |
|
|
xpub1 = wallet.master_public_keys.get("x1/") |
|
|
r = self.multi_mpk_dialog(xpub1, 2) |
|
|
r = self.multi_mpk_dialog(xpub1, n - 1) |
|
|
if not r: |
|
|
if not r: |
|
|
return |
|
|
return |
|
|
xpub2, xpub3 = r |
|
|
for i, xpub in enumerate(r): |
|
|
wallet.add_master_public_key("x2/", xpub2) |
|
|
wallet.add_master_public_key("x%d/"%(i+2), xpub) |
|
|
wallet.add_master_public_key("x3/", xpub3) |
|
|
|
|
|
|
|
|
|
|
|
elif action == 'create_accounts': |
|
|
elif action == 'create_accounts': |
|
|
wallet.create_main_account(password) |
|
|
wallet.create_main_account(password) |
|
@ -443,8 +515,10 @@ class InstallWizard(QDialog): |
|
|
else: |
|
|
else: |
|
|
raise BaseException('unknown wallet type') |
|
|
raise BaseException('unknown wallet type') |
|
|
|
|
|
|
|
|
elif t in ['2of2', '2of3']: |
|
|
elif re.match('(\d+)of(\d+)', t): |
|
|
key_list = self.multi_seed_dialog(1 if t == '2of2' else 2) |
|
|
n = int(re.match('(\d+)of(\d+)', t).group(2)) |
|
|
|
|
|
print t, n |
|
|
|
|
|
key_list = self.multi_seed_dialog(n - 1) |
|
|
if not key_list: |
|
|
if not key_list: |
|
|
return |
|
|
return |
|
|
password = self.password_dialog() if any(map(lambda x: Wallet.is_seed(x) or Wallet.is_xprv(x), key_list)) else None |
|
|
password = self.password_dialog() if any(map(lambda x: Wallet.is_seed(x) or Wallet.is_xprv(x), key_list)) else None |
|
|