commit e461c1c818e5ffff7a510d372661a0e7eb3482c3
parent 6b68968d045abe4a1e2c1ee9fa27e8e040e15114
Author: Neil Booth <kyuupichan@gmail.com>
Date: Sat, 30 Jan 2016 12:20:05 +0900
Create hw_wallet directory for common code
Quite a lot of code under trezor/ can be shared with the
Ledger code. This is the first step for wallets.
Diffstat:
3 files changed, 110 insertions(+), 86 deletions(-)
diff --git a/plugins/hw_wallet/__init__.py b/plugins/hw_wallet/__init__.py
@@ -0,0 +1 @@
+from hw_wallet import BIP44_HW_Wallet
diff --git a/plugins/hw_wallet/hw_wallet.py b/plugins/hw_wallet/hw_wallet.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python2
+# -*- mode: python -*-
+#
+# Electrum - lightweight Bitcoin client
+# Copyright (C) 2016 The Electrum developers
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from struct import pack
+
+from electrum.wallet import BIP44_Wallet
+
+class BIP44_HW_Wallet(BIP44_Wallet):
+ '''A BIP44 hardware wallet base class.'''
+ # Derived classes must set:
+ # - device
+ # - DEVICE_IDS
+ # - wallet_type
+
+ restore_wallet_class = BIP44_Wallet
+ max_change_outputs = 1
+
+ def __init__(self, storage):
+ BIP44_Wallet.__init__(self, storage)
+ # After timeout seconds we clear the device session
+ self.session_timeout = storage.get('session_timeout', 180)
+ # Errors and other user interaction is done through the wallet's
+ # handler. The handler is per-window and preserved across
+ # device reconnects
+ self.handler = None
+ self.force_watching_only = True
+
+ def set_session_timeout(self, seconds):
+ self.print_error("setting session timeout to %d seconds" % seconds)
+ self.session_timeout = seconds
+ self.storage.put('session_timeout', seconds)
+
+ def unpaired(self):
+ '''A device paired with the wallet was diconnected. This can be
+ called in any thread context.'''
+ self.print_error("unpaired")
+ self.force_watching_only = True
+ self.handler.watching_only_changed()
+
+ def paired(self):
+ '''A device paired with the wallet was (re-)connected. This can be
+ called in any thread context.'''
+ self.print_error("paired")
+ self.force_watching_only = False
+ self.handler.watching_only_changed()
+
+ def timeout(self):
+ '''Called when the wallet session times out. Note this is called from
+ the Plugins thread.'''
+ client = self.get_client(force_pair=False)
+ if client:
+ client.clear_session()
+ self.print_error("timed out")
+
+ def get_action(self):
+ pass
+
+ def can_create_accounts(self):
+ return True
+
+ def can_export(self):
+ return False
+
+ def is_watching_only(self):
+ '''The wallet is watching-only if its trezor device is unpaired.'''
+ assert not self.has_seed()
+ return self.force_watching_only
+
+ def can_change_password(self):
+ return False
+
+ def get_client(self, force_pair=True):
+ return self.plugin.get_client(self, force_pair)
+
+ def first_address(self):
+ '''Used to check a hardware wallet matches a software wallet'''
+ account = self.accounts.get('0')
+ derivation = self.address_derivation('0', 0, 0)
+ return (account.first_address()[0] if account else None, derivation)
+
+ def derive_xkeys(self, root, derivation, password):
+ if self.master_public_keys.get(self.root_name):
+ return BIP44_wallet.derive_xkeys(self, root, derivation, password)
+
+ # When creating a wallet we need to ask the device for the
+ # master public key
+ xpub = self.get_public_key(derivation)
+ return xpub, None
+
+ def i4b(self, x):
+ return pack('>I', x)
diff --git a/plugins/trezor/plugin.py b/plugins/trezor/plugin.py
@@ -5,7 +5,6 @@ import time
from binascii import unhexlify
from functools import partial
-from struct import pack
from electrum.account import BIP32_Account
from electrum.bitcoin import (bc_address_to_hash_160, xpub_from_pubkey,
@@ -15,7 +14,7 @@ from electrum.i18n import _
from electrum.plugins import BasePlugin, hook
from electrum.transaction import (deserialize, is_extended_pubkey,
Transaction, x_to_xpub)
-from electrum.wallet import BIP44_Wallet
+from ..hw_wallet import BIP44_HW_Wallet
from electrum.util import ThreadJob
@@ -25,87 +24,7 @@ TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4)
class DeviceDisconnectedError(Exception):
pass
-class TrezorCompatibleWallet(BIP44_Wallet):
- # Extend BIP44 Wallet as required by hardware implementation.
- # Derived classes must set:
- # - device
- # - DEVICE_IDS
- # - wallet_type
-
- restore_wallet_class = BIP44_Wallet
- max_change_outputs = 1
-
- def __init__(self, storage):
- BIP44_Wallet.__init__(self, storage)
- # After timeout seconds we clear the device session
- self.session_timeout = storage.get('session_timeout', 180)
- # Errors and other user interaction is done through the wallet's
- # handler. The handler is per-window and preserved across
- # device reconnects
- self.handler = None
- self.force_watching_only = True
-
- def set_session_timeout(self, seconds):
- self.print_error("setting session timeout to %d seconds" % seconds)
- self.session_timeout = seconds
- self.storage.put('session_timeout', seconds)
-
- def unpaired(self):
- '''A device paired with the wallet was diconnected. This can be
- called in any thread context.'''
- self.print_error("unpaired")
- self.force_watching_only = True
- self.handler.watching_only_changed()
-
- def paired(self):
- '''A device paired with the wallet was (re-)connected. This can be
- called in any thread context.'''
- self.print_error("paired")
- self.force_watching_only = False
- self.handler.watching_only_changed()
-
- def timeout(self):
- '''Called when the wallet session times out. Note this is called from
- the Plugins thread.'''
- client = self.get_client(force_pair=False)
- if client:
- client.clear_session()
- self.print_error("timed out")
-
- def get_action(self):
- pass
-
- def can_create_accounts(self):
- return True
-
- def can_export(self):
- return False
-
- def is_watching_only(self):
- '''The wallet is watching-only if its trezor device is unpaired.'''
- assert not self.has_seed()
- return self.force_watching_only
-
- def can_change_password(self):
- return False
-
- def get_client(self, force_pair=True):
- return self.plugin.get_client(self, force_pair)
-
- def first_address(self):
- '''Used to check a hardware wallet matches a software wallet'''
- account = self.accounts.get('0')
- derivation = self.address_derivation('0', 0, 0)
- return (account.first_address()[0] if account else None, derivation)
-
- def derive_xkeys(self, root, derivation, password):
- if self.master_public_keys.get(self.root_name):
- return BIP44_wallet.derive_xkeys(self, root, derivation, password)
-
- # When creating a wallet we need to ask the device for the
- # master public key
- xpub = self.get_public_key(derivation)
- return xpub, None
+class TrezorCompatibleWallet(BIP44_HW_Wallet):
def get_public_key(self, bip32_path):
client = self.get_client()
@@ -116,9 +35,6 @@ class TrezorCompatibleWallet(BIP44_Wallet):
+ node.chain_code + node.public_key)
return EncodeBase58Check(xpub)
- def i4b(self, x):
- return pack('>I', x)
-
def decrypt_message(self, pubkey, message, password):
address = public_key_to_bc_address(pubkey.decode('hex'))
client = self.get_client()