merge upstream, fix setup.py conflict
This commit is contained in:
@@ -106,10 +106,8 @@ class Plugin(BasePlugin):
|
||||
button.clicked.connect(handler)
|
||||
|
||||
def _audio_interface(self):
|
||||
return amodem.audio.Interface(
|
||||
config=self.modem_config,
|
||||
name=self.library_name
|
||||
)
|
||||
interface = amodem.audio.Interface(config=self.modem_config)
|
||||
return interface.load(self.library_name)
|
||||
|
||||
def _send(self, parent, blob):
|
||||
def sender_thread():
|
||||
|
||||
@@ -15,7 +15,7 @@ from electrum.bitcoin import EncodeBase58Check, DecodeBase58Check, public_key_to
|
||||
from electrum.i18n import _
|
||||
from electrum.plugins import BasePlugin, hook
|
||||
from electrum.transaction import deserialize
|
||||
from electrum.wallet import NewWallet
|
||||
from electrum.wallet import BIP32_HD_Wallet
|
||||
|
||||
from electrum.util import format_satoshis
|
||||
import hashlib
|
||||
@@ -45,19 +45,21 @@ class Plugin(BasePlugin):
|
||||
def __init__(self, gui, name):
|
||||
BasePlugin.__init__(self, gui, name)
|
||||
self._is_available = self._init()
|
||||
self.wallet = None
|
||||
electrum.wallet.wallet_types.append(('hardware', 'btchip', _("BTChip wallet"), BTChipWallet))
|
||||
|
||||
self.wallet = None
|
||||
if self._is_available:
|
||||
electrum.wallet.wallet_types.append(('hardware', 'btchip', _("BTChip wallet"), BTChipWallet))
|
||||
|
||||
def _init(self):
|
||||
return BTCHIP
|
||||
|
||||
def is_available(self):
|
||||
if self.wallet is None:
|
||||
return self._is_available
|
||||
if self.wallet.storage.get('wallet_type') == 'btchip':
|
||||
return True
|
||||
return False
|
||||
def is_available(self):
|
||||
if not self._is_available:
|
||||
return False
|
||||
if not self.wallet:
|
||||
return False
|
||||
if self.wallet.storage.get('wallet_type') != 'btchip':
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_enabled(self, enabled):
|
||||
self.wallet.storage.put('use_' + self.name, enabled)
|
||||
@@ -65,19 +67,30 @@ class Plugin(BasePlugin):
|
||||
def is_enabled(self):
|
||||
if not self.is_available():
|
||||
return False
|
||||
|
||||
if not self.wallet or self.wallet.storage.get('wallet_type') == 'btchip':
|
||||
return True
|
||||
|
||||
return self.wallet.storage.get('use_' + self.name) is True
|
||||
if self.wallet.has_seed():
|
||||
return False
|
||||
return True
|
||||
|
||||
def enable(self):
|
||||
return BasePlugin.enable(self)
|
||||
|
||||
def btchip_is_connected(self):
|
||||
try:
|
||||
self.wallet.get_client().getFirmwareVersion()
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
@hook
|
||||
def load_wallet(self, wallet):
|
||||
self.wallet = wallet
|
||||
|
||||
if self.btchip_is_connected():
|
||||
if not self.wallet.check_proper_device():
|
||||
QMessageBox.information(self.window, _('Error'), _("This wallet does not match your BTChip device"), _('OK'))
|
||||
self.wallet.force_watching_only = True
|
||||
else:
|
||||
QMessageBox.information(self.window, _('Error'), _("BTChip device not detected.\nContinuing in watching-only mode."), _('OK'))
|
||||
self.wallet.force_watching_only = True
|
||||
|
||||
@hook
|
||||
def installwizard_restore(self, wizard, storage):
|
||||
if storage.get('wallet_type') != 'btchip':
|
||||
@@ -98,16 +111,18 @@ class Plugin(BasePlugin):
|
||||
except Exception as e:
|
||||
tx.error = str(e)
|
||||
|
||||
class BTChipWallet(NewWallet):
|
||||
class BTChipWallet(BIP32_HD_Wallet):
|
||||
wallet_type = 'btchip'
|
||||
root_derivation = "m/44'/0'"
|
||||
|
||||
def __init__(self, storage):
|
||||
NewWallet.__init__(self, storage)
|
||||
BIP32_HD_Wallet.__init__(self, storage)
|
||||
self.transport = None
|
||||
self.client = None
|
||||
self.mpk = None
|
||||
self.device_checked = False
|
||||
self.signing = False
|
||||
self.force_watching_only = False
|
||||
|
||||
def give_error(self, message, clear_client = False):
|
||||
if not self.signing:
|
||||
@@ -129,11 +144,8 @@ class BTChipWallet(NewWallet):
|
||||
def can_change_password(self):
|
||||
return False
|
||||
|
||||
def has_seed(self):
|
||||
return False
|
||||
|
||||
def is_watching_only(self):
|
||||
return False
|
||||
return self.force_watching_only
|
||||
|
||||
def get_client(self, noPin=False):
|
||||
if not BTCHIP:
|
||||
@@ -258,9 +270,6 @@ class BTChipWallet(NewWallet):
|
||||
def get_master_public_key(self):
|
||||
try:
|
||||
if not self.mpk:
|
||||
self.get_client() # prompt for the PIN if necessary
|
||||
if not self.check_proper_device():
|
||||
self.give_error('Wrong device or password')
|
||||
self.mpk = self.get_public_key("44'/0'")
|
||||
return self.mpk
|
||||
except Exception, e:
|
||||
@@ -278,6 +287,7 @@ class BTChipWallet(NewWallet):
|
||||
|
||||
def sign_message(self, address, message, password):
|
||||
use2FA = False
|
||||
self.signing = True
|
||||
self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
||||
if not self.check_proper_device():
|
||||
self.give_error('Wrong device or password')
|
||||
@@ -298,11 +308,15 @@ class BTChipWallet(NewWallet):
|
||||
self.get_client(True)
|
||||
signature = self.get_client().signMessageSign(pin)
|
||||
except Exception, e:
|
||||
self.give_error(e, True)
|
||||
if e.sw == 0x6a80:
|
||||
self.give_error("Unfortunately, this message cannot be signed by BTChip. Only alphanumerical messages shorter than 140 characters are supported. Please remove any extra characters (tab, carriage return) and retry.")
|
||||
else:
|
||||
self.give_error(e, True)
|
||||
finally:
|
||||
if waitDialog.waiting:
|
||||
waitDialog.emit(SIGNAL('dongle_done'))
|
||||
self.client.bad = use2FA
|
||||
self.signing = False
|
||||
|
||||
# Parse the ASN.1 signature
|
||||
|
||||
|
||||
@@ -93,14 +93,9 @@ class Plugin(BasePlugin):
|
||||
def init_qt(self, gui):
|
||||
self.win = gui.main_window
|
||||
self.win.connect(self.win, SIGNAL('cosigner:receive'), self.on_receive)
|
||||
if self.listener is None:
|
||||
self.listener = Listener(self)
|
||||
self.listener.start()
|
||||
|
||||
def enable(self):
|
||||
self.set_enabled(True)
|
||||
if self.win.wallet:
|
||||
self.load_wallet(self.win.wallet)
|
||||
return True
|
||||
|
||||
def is_available(self):
|
||||
@@ -113,6 +108,9 @@ class Plugin(BasePlugin):
|
||||
self.wallet = wallet
|
||||
if not self.is_available():
|
||||
return
|
||||
if self.listener is None:
|
||||
self.listener = Listener(self)
|
||||
self.listener.start()
|
||||
mpk = self.wallet.get_master_public_keys()
|
||||
self.cosigner_list = []
|
||||
for key, xpub in mpk.items():
|
||||
|
||||
@@ -49,17 +49,20 @@ class Plugin(BasePlugin):
|
||||
self._is_available = self._init()
|
||||
self._requires_settings = True
|
||||
self.wallet = None
|
||||
electrum.wallet.wallet_types.append(('hardware', 'trezor', _("Trezor wallet"), TrezorWallet))
|
||||
if self._is_available:
|
||||
electrum.wallet.wallet_types.append(('hardware', 'trezor', _("Trezor wallet"), TrezorWallet))
|
||||
|
||||
def _init(self):
|
||||
return TREZOR
|
||||
|
||||
def is_available(self):
|
||||
if self.wallet is None:
|
||||
return self._is_available
|
||||
if self.wallet.storage.get('wallet_type') == 'trezor':
|
||||
return True
|
||||
return False
|
||||
if not self._is_available:
|
||||
return False
|
||||
if not self.wallet:
|
||||
return False
|
||||
if self.wallet.storage.get('wallet_type') != 'trezor':
|
||||
return False
|
||||
return True
|
||||
|
||||
def requires_settings(self):
|
||||
return self._requires_settings
|
||||
@@ -70,11 +73,9 @@ class Plugin(BasePlugin):
|
||||
def is_enabled(self):
|
||||
if not self.is_available():
|
||||
return False
|
||||
|
||||
if not self.wallet or self.wallet.storage.get('wallet_type') == 'trezor':
|
||||
return True
|
||||
|
||||
return self.wallet.storage.get('use_' + self.name) is True
|
||||
if self.wallet.has_seed():
|
||||
return False
|
||||
return True
|
||||
|
||||
def enable(self):
|
||||
return BasePlugin.enable(self)
|
||||
@@ -93,28 +94,34 @@ class Plugin(BasePlugin):
|
||||
@hook
|
||||
def close_wallet(self):
|
||||
print_error("trezor: clear session")
|
||||
if self.wallet.client:
|
||||
if self.wallet and self.wallet.client:
|
||||
self.wallet.client.clear_session()
|
||||
|
||||
@hook
|
||||
def load_wallet(self, wallet):
|
||||
self.wallet = wallet
|
||||
if self.trezor_is_connected():
|
||||
if not self.wallet.check_proper_device():
|
||||
QMessageBox.information(self.window, _('Error'), _("This wallet does not match your Trezor device"), _('OK'))
|
||||
self.wallet.force_watching_only = True
|
||||
else:
|
||||
QMessageBox.information(self.window, _('Error'), _("Trezor device not detected.\nContinuing in watching-only mode."), _('OK'))
|
||||
self.wallet.force_watching_only = True
|
||||
|
||||
@hook
|
||||
def installwizard_restore(self, wizard, storage):
|
||||
if storage.get('wallet_type') != 'trezor':
|
||||
return
|
||||
wallet = TrezorWallet(storage)
|
||||
try:
|
||||
wallet.create_main_account(None)
|
||||
except BaseException as e:
|
||||
QMessageBox.information(None, _('Error'), str(e), _('OK'))
|
||||
seed = wizard.enter_seed_dialog("Enter your Trezor seed", None, func=lambda x:True)
|
||||
if not seed:
|
||||
return
|
||||
wallet = TrezorWallet(storage)
|
||||
self.wallet = wallet
|
||||
password = wizard.password_dialog()
|
||||
wallet.add_seed(seed, password)
|
||||
wallet.add_cosigner_seed(' '.join(seed.split()), 'x/', password)
|
||||
wallet.create_main_account(password)
|
||||
# disable trezor plugin
|
||||
self.set_enabled(False)
|
||||
return wallet
|
||||
|
||||
@hook
|
||||
@@ -161,6 +168,8 @@ class Plugin(BasePlugin):
|
||||
return False
|
||||
|
||||
|
||||
from electrum.wallet import pw_decode, bip32_private_derivation, bip32_root
|
||||
|
||||
class TrezorWallet(BIP32_HD_Wallet):
|
||||
wallet_type = 'trezor'
|
||||
root_derivation = "m/44'/0'"
|
||||
@@ -171,6 +180,7 @@ class TrezorWallet(BIP32_HD_Wallet):
|
||||
self.client = None
|
||||
self.mpk = None
|
||||
self.device_checked = False
|
||||
self.force_watching_only = False
|
||||
|
||||
def get_action(self):
|
||||
if not self.accounts:
|
||||
@@ -188,11 +198,8 @@ class TrezorWallet(BIP32_HD_Wallet):
|
||||
def can_change_password(self):
|
||||
return False
|
||||
|
||||
def has_seed(self):
|
||||
return False
|
||||
|
||||
def is_watching_only(self):
|
||||
return False
|
||||
return self.force_watching_only
|
||||
|
||||
def get_client(self):
|
||||
if not TREZOR:
|
||||
@@ -221,10 +228,23 @@ class TrezorWallet(BIP32_HD_Wallet):
|
||||
def create_main_account(self, password):
|
||||
self.create_account('Main account', None) #name, empty password
|
||||
|
||||
def mnemonic_to_seed(self, mnemonic, passphrase):
|
||||
# trezor uses bip39
|
||||
import pbkdf2, hashlib, hmac
|
||||
PBKDF2_ROUNDS = 2048
|
||||
mnemonic = ' '.join(mnemonic.split())
|
||||
return pbkdf2.PBKDF2(mnemonic, 'mnemonic' + passphrase, iterations = PBKDF2_ROUNDS, macmodule = hmac, digestmodule = hashlib.sha512).read(64)
|
||||
|
||||
def derive_xkeys(self, root, derivation, password):
|
||||
derivation = derivation.replace(self.root_name,"44'/0'/")
|
||||
xpub = self.get_public_key(derivation)
|
||||
return xpub, None
|
||||
x = self.master_private_keys.get(root)
|
||||
if x:
|
||||
root_xprv = pw_decode(x, password)
|
||||
xprv, xpub = bip32_private_derivation(root_xprv, root, derivation)
|
||||
return xpub, xprv
|
||||
else:
|
||||
derivation = derivation.replace(self.root_name,"44'/0'/")
|
||||
xpub = self.get_public_key(derivation)
|
||||
return xpub, None
|
||||
|
||||
def get_public_key(self, bip32_path):
|
||||
address_n = self.get_client().expand_path(bip32_path)
|
||||
|
||||
@@ -223,8 +223,8 @@ class Plugin(BasePlugin):
|
||||
+ _("For more information, visit") + " <a href=\"https://api.trustedcoin.com/#/electrum-help\">https://api.trustedcoin.com/#/electrum-help</a>"
|
||||
|
||||
def is_available(self):
|
||||
if self.wallet is None:
|
||||
return True
|
||||
if not self.wallet:
|
||||
return False
|
||||
if self.wallet.storage.get('wallet_type') == '2fa':
|
||||
return True
|
||||
return False
|
||||
@@ -238,10 +238,6 @@ class Plugin(BasePlugin):
|
||||
def is_enabled(self):
|
||||
if not self.is_available():
|
||||
return False
|
||||
if not self.wallet:
|
||||
return True
|
||||
if self.wallet.storage.get('wallet_type') != '2fa':
|
||||
return False
|
||||
if self.wallet.master_private_keys.get('x2/'):
|
||||
return False
|
||||
return True
|
||||
@@ -344,15 +340,13 @@ class Plugin(BasePlugin):
|
||||
|
||||
@hook
|
||||
def load_wallet(self, wallet):
|
||||
self.wallet = wallet
|
||||
if self.is_enabled():
|
||||
self.trustedcoin_button = StatusBarButton( QIcon(":icons/trustedcoin.png"), _("Network"), self.settings_dialog)
|
||||
self.window.statusBar().addPermanentWidget(self.trustedcoin_button)
|
||||
self.xpub = self.wallet.master_public_keys.get('x1/')
|
||||
self.user_id = self.get_user_id()[1]
|
||||
t = threading.Thread(target=self.request_billing_info)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
self.trustedcoin_button = StatusBarButton( QIcon(":icons/trustedcoin.png"), _("Network"), self.settings_dialog)
|
||||
self.window.statusBar().addPermanentWidget(self.trustedcoin_button)
|
||||
self.xpub = self.wallet.master_public_keys.get('x1/')
|
||||
self.user_id = self.get_user_id()[1]
|
||||
t = threading.Thread(target=self.request_billing_info)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
@hook
|
||||
def close_wallet(self):
|
||||
@@ -481,6 +475,7 @@ class Plugin(BasePlugin):
|
||||
return 0
|
||||
# trustedcoin won't charge if the total inputs is lower than their fee
|
||||
price = int(self.price_per_tx.get(1))
|
||||
assert price <= 100000
|
||||
if tx.input_value() < price:
|
||||
print_error("not charging for this tx")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user