URI: 
       tShare non-GUI plugin parts of KeepKey and Trezor - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 33e57fe5a79c1b83aa0f21087eab9d69f36b09e7
   DIR parent 42719cd0a9df28b62fe82bb711e9145666ae000d
  HTML Author: Neil Booth <kyuupichan@gmail.com>
       Date:   Sat, 26 Dec 2015 19:42:57 +0900
       
       Share non-GUI plugin parts of KeepKey and Trezor
       
       Diffstat:
         M plugins/keepkey/keepkey.py          |     211 ++-----------------------------
         A plugins/trezor/plugin_generic.py    |     206 +++++++++++++++++++++++++++++++
         M plugins/trezor/trezor.py            |     202 ++-----------------------------
       
       3 files changed, 227 insertions(+), 392 deletions(-)
       ---
   DIR diff --git a/plugins/keepkey/keepkey.py b/plugins/keepkey/keepkey.py
       t@@ -1,19 +1,9 @@
       -from binascii import unhexlify
       -
       -import electrum
       -from electrum import bitcoin
       -
       -from electrum.account import BIP32_Account
       -from electrum.bitcoin import bc_address_to_hash_160, xpub_from_pubkey
       -from electrum.i18n import _
       -from electrum.plugins import BasePlugin, hook
       -from electrum.transaction import deserialize, is_extended_pubkey
        from electrum.wallet import BIP32_Hardware_Wallet
       -from electrum.util import print_error
       +
        from plugins.trezor.gui_mixin import GuiMixin
       +from plugins.trezor.plugin_generic import TrezorCompatiblePlugin
        
        try:
       -    from keepkeylib.client import types
            from keepkeylib.client import proto, BaseClient, ProtocolMixin
            from keepkeylib.transport import ConnectionError
            from keepkeylib.transport_hid import HidTransport
       t@@ -21,12 +11,6 @@ try:
        except ImportError:
            KEEPKEY = False
        
       -import keepkeylib.ckd_public as ckd_public
       -
       -def give_error(message):
       -    print_error(message)
       -    raise Exception(message)
       -
        
        class KeepKeyWallet(BIP32_Hardware_Wallet):
            wallet_type = 'keepkey'
       t@@ -34,50 +18,18 @@ class KeepKeyWallet(BIP32_Hardware_Wallet):
            device = 'KeepKey'
        
        
       -class KeepKeyPlugin(BasePlugin):
       +class KeepKeyPlugin(TrezorCompatiblePlugin):
       +    wallet_type = 'keepkey'
       +    import keepkeylib.ckd_public as ckd_public
       +    from keepkeylib.client import types
        
       -    def __init__(self, parent, config, name):
       -        BasePlugin.__init__(self, parent, config, name)
       -        self._is_available = self._init()
       -        self.wallet = None
       -        self.handler = None
       -        self.client = None
       -        self.transport = None
       +    @staticmethod
       +    def libraries_available():
       +        return KEEPKEY
        
            def constructor(self, s):
                return KeepKeyWallet(s)
        
       -    def _init(self):
       -        return KEEPKEY
       -
       -    def is_available(self):
       -        if not self._is_available:
       -            return False
       -        if not self.wallet:
       -            return False
       -        if self.wallet.storage.get('wallet_type') != 'keepkey':
       -            return False
       -        return True
       -
       -    def set_enabled(self, enabled):
       -        self.wallet.storage.put('use_' + self.name, enabled)
       -
       -    def is_enabled(self):
       -        if not self.is_available():
       -            return False
       -        if self.wallet.has_seed():
       -            return False
       -        return True
       -
       -    def compare_version(self, major, minor=0, patch=0):
       -        features = self.get_client().features
       -        v = [features.major_version, features.minor_version, features.patch_version]
       -        self.print_error('firmware version', v)
       -        return cmp(v, [major, minor, patch])
       -
       -    def atleast_version(self, major, minor=0, patch=0):
       -        return self.compare_version(major, minor, patch) >= 0
       -
            def get_client(self):
                if not KEEPKEY:
                    give_error('please install github.com/keepkey/python-keepkey')
       t@@ -96,151 +48,6 @@ class KeepKeyPlugin(BasePlugin):
                        give_error('Outdated KeepKey firmware. Please update the firmware from https://www.keepkey.com')
                return self.client
        
       -    @hook
       -    def close_wallet(self):
       -        print_error("keepkey: clear session")
       -        if self.client:
       -            self.client.clear_session()
       -            self.client.transport.close()
       -            self.client = None
       -        self.wallet = None
       -
       -
       -    def show_address(self, address):
       -        self.wallet.check_proper_device()
       -        try:
       -            address_path = self.wallet.address_id(address)
       -            address_n = self.get_client().expand_path(address_path)
       -        except Exception, e:
       -            give_error(e)
       -        try:
       -            self.get_client().get_address('Bitcoin', address_n, True)
       -        except Exception, e:
       -            give_error(e)
       -        finally:
       -            self.handler.stop()
       -
       -
       -    def sign_transaction(self, tx, prev_tx, xpub_path):
       -        self.prev_tx = prev_tx
       -        self.xpub_path = xpub_path
       -        client = self.get_client()
       -        inputs = self.tx_inputs(tx, True)
       -        outputs = self.tx_outputs(tx)
       -        try:
       -            signed_tx = client.sign_tx('Bitcoin', inputs, outputs)[1]
       -        except Exception, e:
       -            self.handler.stop()
       -            give_error(e)
       -
       -        self.handler.stop()
       -
       -        raw = signed_tx.encode('hex')
       -        tx.update_signatures(raw)
       -
       -
       -    def tx_inputs(self, tx, for_sig=False):
       -        inputs = []
       -        for txin in tx.inputs:
       -            txinputtype = types.TxInputType()
       -            if txin.get('is_coinbase'):
       -                prev_hash = "\0"*32
       -                prev_index = 0xffffffff # signed int -1
       -            else:
       -                if for_sig:
       -                    x_pubkeys = txin['x_pubkeys']
       -                    if len(x_pubkeys) == 1:
       -                        x_pubkey = x_pubkeys[0]
       -                        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -                        xpub_n = self.get_client().expand_path(self.xpub_path[xpub])
       -                        txinputtype.address_n.extend(xpub_n + s)
       -                    else:
       -                        def f(x_pubkey):
       -                            if is_extended_pubkey(x_pubkey):
       -                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -                            else:
       -                                xpub = xpub_from_pubkey(x_pubkey.decode('hex'))
       -                                s = []
       -                            node = ckd_public.deserialize(xpub)
       -                            return types.HDNodePathType(node=node, address_n=s)
       -                        pubkeys = map(f, x_pubkeys)
       -                        multisig = types.MultisigRedeemScriptType(
       -                            pubkeys=pubkeys,
       -                            signatures=map(lambda x: x.decode('hex') if x else '', txin.get('signatures')),
       -                            m=txin.get('num_sig'),
       -                        )
       -                        txinputtype = types.TxInputType(
       -                            script_type=types.SPENDMULTISIG,
       -                            multisig= multisig
       -                        )
       -                        # find which key is mine
       -                        for x_pubkey in x_pubkeys:
       -                            if is_extended_pubkey(x_pubkey):
       -                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -                                if xpub in self.xpub_path:
       -                                    xpub_n = self.get_client().expand_path(self.xpub_path[xpub])
       -                                    txinputtype.address_n.extend(xpub_n + s)
       -                                    break
       -
       -                prev_hash = unhexlify(txin['prevout_hash'])
       -                prev_index = txin['prevout_n']
       -
       -            txinputtype.prev_hash = prev_hash
       -            txinputtype.prev_index = prev_index
       -
       -            if 'scriptSig' in txin:
       -                script_sig = txin['scriptSig'].decode('hex')
       -                txinputtype.script_sig = script_sig
       -
       -            if 'sequence' in txin:
       -                sequence = txin['sequence']
       -                txinputtype.sequence = sequence
       -
       -            inputs.append(txinputtype)
       -
       -        return inputs
       -
       -    def tx_outputs(self, tx):
       -        outputs = []
       -
       -        for type, address, amount in tx.outputs:
       -            assert type == 'address'
       -            txoutputtype = types.TxOutputType()
       -            if self.wallet.is_change(address):
       -                address_path = self.wallet.address_id(address)
       -                address_n = self.get_client().expand_path(address_path)
       -                txoutputtype.address_n.extend(address_n)
       -            else:
       -                txoutputtype.address = address
       -            txoutputtype.amount = amount
       -            addrtype, hash_160 = bc_address_to_hash_160(address)
       -            if addrtype == 0:
       -                txoutputtype.script_type = types.PAYTOADDRESS
       -            elif addrtype == 5:
       -                txoutputtype.script_type = types.PAYTOSCRIPTHASH
       -            else:
       -                raise BaseException('addrtype')
       -            outputs.append(txoutputtype)
       -
       -        return outputs
       -
       -    def electrum_tx_to_txtype(self, tx):
       -        t = types.TransactionType()
       -        d = deserialize(tx.raw)
       -        t.version = d['version']
       -        t.lock_time = d['lockTime']
       -        inputs = self.tx_inputs(tx)
       -        t.inputs.extend(inputs)
       -        for vout in d['outputs']:
       -            o = t.bin_outputs.add()
       -            o.amount = vout['value']
       -            o.script_pubkey = vout['scriptPubKey'].decode('hex')
       -        return t
       -
       -    def get_tx(self, tx_hash):
       -        tx = self.prev_tx[tx_hash]
       -        tx.deserialize()
       -        return self.electrum_tx_to_txtype(tx)
        
        if KEEPKEY:
            class QtGuiKeepKeyClient(ProtocolMixin, GuiMixin, BaseClient):
   DIR diff --git a/plugins/trezor/plugin_generic.py b/plugins/trezor/plugin_generic.py
       t@@ -0,0 +1,206 @@
       +from binascii import unhexlify
       +
       +from electrum.account import BIP32_Account
       +from electrum.bitcoin import bc_address_to_hash_160, xpub_from_pubkey
       +from electrum.i18n import _
       +from electrum.plugins import BasePlugin, hook
       +from electrum.transaction import deserialize, is_extended_pubkey
       +
       +class TrezorCompatiblePlugin(BasePlugin):
       +    # Derived classes provide:
       +
       +    #  libraries_available()
       +    #  constructor()
       +    #  ckd_public
       +    #  types
       +    #  wallet_type
       +
       +    def __init__(self, parent, config, name):
       +        BasePlugin.__init__(self, parent, config, name)
       +        self.wallet = None
       +        self.handler = None
       +        self.client = None
       +        self.transport = None
       +
       +    def constructor(self, s):
       +        raise NotImplementedError
       +
       +    @staticmethod
       +    def libraries_available():
       +        raise NotImplementedError
       +
       +    def give_error(self, message):
       +        self.print_error(message)
       +        raise Exception(message)
       +
       +    def is_available(self):
       +        if not self.libraries_available():
       +            return False
       +        if not self.wallet:
       +            return False
       +        if self.wallet.storage.get('wallet_type') != self.wallet_type:
       +            return False
       +        return True
       +
       +    def set_enabled(self, enabled):
       +        self.wallet.storage.put('use_' + self.name, enabled)
       +
       +    def is_enabled(self):
       +        if not self.is_available():
       +            return False
       +        if self.wallet.has_seed():
       +            return False
       +        return True
       +
       +    def compare_version(self, major, minor=0, patch=0):
       +        features = self.get_client().features
       +        v = [features.major_version, features.minor_version, features.patch_version]
       +        self.print_error('firmware version', v)
       +        return cmp(v, [major, minor, patch])
       +
       +    def atleast_version(self, major, minor=0, patch=0):
       +        return self.compare_version(major, minor, patch) >= 0
       +
       +    @hook
       +    def close_wallet(self):
       +        self.print_error("clear session")
       +        if self.client:
       +            self.client.clear_session()
       +            self.client.transport.close()
       +            self.client = None
       +        self.wallet = None
       +
       +    def sign_transaction(self, tx, prev_tx, xpub_path):
       +        self.prev_tx = prev_tx
       +        self.xpub_path = xpub_path
       +        client = self.get_client()
       +        inputs = self.tx_inputs(tx, True)
       +        outputs = self.tx_outputs(tx)
       +        try:
       +            signed_tx = client.sign_tx('Bitcoin', inputs, outputs)[1]
       +        except Exception as e:
       +            self.give_error(e)
       +        finally:
       +            self.handler.stop()
       +        raw = signed_tx.encode('hex')
       +        tx.update_signatures(raw)
       +
       +    def show_address(self, address):
       +        client = self.get_client()
       +        self.wallet.check_proper_device()
       +        try:
       +            address_path = self.wallet.address_id(address)
       +            address_n = client.expand_path(address_path)
       +        except Exception as e:
       +            self.give_error(e)
       +        try:
       +            client.get_address('Bitcoin', address_n, True)
       +        except Exception as e:
       +            self.give_error(e)
       +        finally:
       +            self.handler.stop()
       +
       +    def tx_inputs(self, tx, for_sig=False):
       +        client = self.get_client()
       +        inputs = []
       +        for txin in tx.inputs:
       +            txinputtype = self.types.TxInputType()
       +            if txin.get('is_coinbase'):
       +                prev_hash = "\0"*32
       +                prev_index = 0xffffffff # signed int -1
       +            else:
       +                if for_sig:
       +                    x_pubkeys = txin['x_pubkeys']
       +                    if len(x_pubkeys) == 1:
       +                        x_pubkey = x_pubkeys[0]
       +                        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +                        xpub_n = client.expand_path(self.xpub_path[xpub])
       +                        txinputtype.address_n.extend(xpub_n + s)
       +                    else:
       +                        def f(x_pubkey):
       +                            if is_extended_pubkey(x_pubkey):
       +                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +                            else:
       +                                xpub = xpub_from_pubkey(x_pubkey.decode('hex'))
       +                                s = []
       +                            node = ckd_public.deserialize(xpub)
       +                            return self.types.HDNodePathType(node=node, address_n=s)
       +                        pubkeys = map(f, x_pubkeys)
       +                        multisig = self.types.MultisigRedeemScriptType(
       +                            pubkeys=pubkeys,
       +                            signatures=map(lambda x: x.decode('hex') if x else '', txin.get('signatures')),
       +                            m=txin.get('num_sig'),
       +                        )
       +                        txinputtype = self.types.TxInputType(
       +                            script_type=self.types.SPENDMULTISIG,
       +                            multisig= multisig
       +                        )
       +                        # find which key is mine
       +                        for x_pubkey in x_pubkeys:
       +                            if is_extended_pubkey(x_pubkey):
       +                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       +                                if xpub in self.xpub_path:
       +                                    xpub_n = client.expand_path(self.xpub_path[xpub])
       +                                    txinputtype.address_n.extend(xpub_n + s)
       +                                    break
       +
       +                prev_hash = unhexlify(txin['prevout_hash'])
       +                prev_index = txin['prevout_n']
       +
       +            txinputtype.prev_hash = prev_hash
       +            txinputtype.prev_index = prev_index
       +
       +            if 'scriptSig' in txin:
       +                script_sig = txin['scriptSig'].decode('hex')
       +                txinputtype.script_sig = script_sig
       +
       +            if 'sequence' in txin:
       +                sequence = txin['sequence']
       +                txinputtype.sequence = sequence
       +
       +            inputs.append(txinputtype)
       +
       +        return inputs
       +
       +    def tx_outputs(self, tx):
       +        client = self.get_client()
       +        outputs = []
       +
       +        for type, address, amount in tx.outputs:
       +            assert type == 'address'
       +            txoutputtype = self.types.TxOutputType()
       +            if self.wallet.is_change(address):
       +                address_path = self.wallet.address_id(address)
       +                address_n = client.expand_path(address_path)
       +                txoutputtype.address_n.extend(address_n)
       +            else:
       +                txoutputtype.address = address
       +            txoutputtype.amount = amount
       +            addrtype, hash_160 = bc_address_to_hash_160(address)
       +            if addrtype == 0:
       +                txoutputtype.script_type = self.types.PAYTOADDRESS
       +            elif addrtype == 5:
       +                txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
       +            else:
       +                raise BaseException('addrtype')
       +            outputs.append(txoutputtype)
       +
       +        return outputs
       +
       +    def electrum_tx_to_txtype(self, tx):
       +        t = self.types.TransactionType()
       +        d = deserialize(tx.raw)
       +        t.version = d['version']
       +        t.lock_time = d['lockTime']
       +        inputs = self.tx_inputs(tx)
       +        t.inputs.extend(inputs)
       +        for vout in d['outputs']:
       +            o = t.bin_outputs.add()
       +            o.amount = vout['value']
       +            o.script_pubkey = vout['scriptPubKey'].decode('hex')
       +        return t
       +
       +    def get_tx(self, tx_hash):
       +        tx = self.prev_tx[tx_hash]
       +        tx.deserialize()
       +        return self.electrum_tx_to_txtype(tx)
   DIR diff --git a/plugins/trezor/trezor.py b/plugins/trezor/trezor.py
       t@@ -1,19 +1,9 @@
       -from binascii import unhexlify
       -
       -import electrum
       -from electrum import bitcoin
       -
       -from electrum.account import BIP32_Account
       -from electrum.bitcoin import bc_address_to_hash_160, xpub_from_pubkey
       -from electrum.i18n import _
       -from electrum.plugins import BasePlugin, hook
       -from electrum.transaction import deserialize, is_extended_pubkey
        from electrum.wallet import BIP32_Hardware_Wallet
       -from electrum.util import print_error
       +
        from plugins.trezor.gui_mixin import GuiMixin
       +from plugins.trezor.plugin_generic import TrezorCompatiblePlugin
        
        try:
       -    from trezorlib.client import types
            from trezorlib.client import proto, BaseClient, ProtocolMixin
            from trezorlib.transport import ConnectionError
            from trezorlib.transport_hid import HidTransport
       t@@ -21,71 +11,32 @@ try:
        except ImportError:
            TREZOR = False
        
       -import trezorlib.ckd_public as ckd_public
       -
       -def give_error(message):
       -    print_error(message)
       -    raise Exception(message)
       -
        
        class TrezorWallet(BIP32_Hardware_Wallet):
            wallet_type = 'trezor'
            root_derivation = "m/44'/0'"
            device = 'Trezor'
        
       +class TrezorPlugin(TrezorCompatiblePlugin):
       +    wallet_type = 'trezor'
       +    import trezorlib.ckd_public as ckd_public
       +    from trezorlib.client import types
        
       -class TrezorPlugin(BasePlugin):
       -
       -    def __init__(self, parent, config, name):
       -        BasePlugin.__init__(self, parent, config, name)
       -        self._is_available = self._init()
       -        self.wallet = None
       -        self.handler = None
       -        self.client = None
       -        self.transport = None
       +    @staticmethod
       +    def libraries_available():
       +        return TREZOR
        
            def constructor(self, s):
                return TrezorWallet(s)
        
       -    def _init(self):
       -        return TREZOR
       -
       -    def is_available(self):
       -        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 set_enabled(self, enabled):
       -        self.wallet.storage.put('use_' + self.name, enabled)
       -
       -    def is_enabled(self):
       -        if not self.is_available():
       -            return False
       -        if self.wallet.has_seed():
       -            return False
       -        return True
       -
       -    def compare_version(self, major, minor=0, patch=0):
       -        features = self.get_client().features
       -        v = [features.major_version, features.minor_version, features.patch_version]
       -        self.print_error('firmware version', v)
       -        return cmp(v, [major, minor, patch])
       -
       -    def atleast_version(self, major, minor=0, patch=0):
       -        return self.compare_version(major, minor, patch) >= 0
       -
            def get_client(self):
                if not TREZOR:
       -            give_error('please install github.com/trezor/python-trezor')
       +            self.give_error('please install github.com/trezor/python-trezor')
        
                if not self.client or self.client.bad:
                    d = HidTransport.enumerate()
                    if not d:
       -                give_error('Could not connect to your Trezor. Please verify the cable is connected and that no other app is using it.')
       +                self.give_error('Could not connect to your Trezor. Please verify the cable is connected and that no other app is using it.')
                    self.transport = HidTransport(d[0])
                    self.client = QtGuiTrezorClient(self.transport)
                    self.client.handler = self.handler
       t@@ -93,138 +44,9 @@ class TrezorPlugin(BasePlugin):
                    self.client.bad = False
                    if not self.atleast_version(1, 2, 1):
                        self.client = None
       -                give_error('Outdated Trezor firmware. Please update the firmware from https://www.mytrezor.com')
       +                self.give_error('Outdated Trezor firmware. Please update the firmware from https://www.mytrezor.com')
                return self.client
        
       -    @hook
       -    def close_wallet(self):
       -        print_error("trezor: clear session")
       -        if self.client:
       -            self.client.clear_session()
       -            self.client.transport.close()
       -            self.client = None
       -        self.wallet = None
       -
       -    def sign_transaction(self, tx, prev_tx, xpub_path):
       -        self.prev_tx = prev_tx
       -        self.xpub_path = xpub_path
       -        client = self.get_client()
       -        inputs = self.tx_inputs(tx, True)
       -        outputs = self.tx_outputs(tx)
       -        #try:
       -        signed_tx = client.sign_tx('Bitcoin', inputs, outputs)[1]
       -        #except Exception, e:
       -        #    give_error(e)
       -        #finally:
       -        self.handler.stop()
       -
       -        raw = signed_tx.encode('hex')
       -        tx.update_signatures(raw)
       -
       -
       -    def tx_inputs(self, tx, for_sig=False):
       -        inputs = []
       -        for txin in tx.inputs:
       -            txinputtype = types.TxInputType()
       -            if txin.get('is_coinbase'):
       -                prev_hash = "\0"*32
       -                prev_index = 0xffffffff # signed int -1
       -            else:
       -                if for_sig:
       -                    x_pubkeys = txin['x_pubkeys']
       -                    if len(x_pubkeys) == 1:
       -                        x_pubkey = x_pubkeys[0]
       -                        xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -                        xpub_n = self.get_client().expand_path(self.xpub_path[xpub])
       -                        txinputtype.address_n.extend(xpub_n + s)
       -                    else:
       -                        def f(x_pubkey):
       -                            if is_extended_pubkey(x_pubkey):
       -                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -                            else:
       -                                xpub = xpub_from_pubkey(x_pubkey.decode('hex'))
       -                                s = []
       -                            node = ckd_public.deserialize(xpub)
       -                            return types.HDNodePathType(node=node, address_n=s)
       -                        pubkeys = map(f, x_pubkeys)
       -                        multisig = types.MultisigRedeemScriptType(
       -                            pubkeys=pubkeys,
       -                            signatures=map(lambda x: x.decode('hex') if x else '', txin.get('signatures')),
       -                            m=txin.get('num_sig'),
       -                        )
       -                        txinputtype = types.TxInputType(
       -                            script_type=types.SPENDMULTISIG,
       -                            multisig= multisig
       -                        )
       -                        # find which key is mine
       -                        for x_pubkey in x_pubkeys:
       -                            if is_extended_pubkey(x_pubkey):
       -                                xpub, s = BIP32_Account.parse_xpubkey(x_pubkey)
       -                                if xpub in self.xpub_path:
       -                                    xpub_n = self.get_client().expand_path(self.xpub_path[xpub])
       -                                    txinputtype.address_n.extend(xpub_n + s)
       -                                    break
       -
       -                prev_hash = unhexlify(txin['prevout_hash'])
       -                prev_index = txin['prevout_n']
       -
       -            txinputtype.prev_hash = prev_hash
       -            txinputtype.prev_index = prev_index
       -
       -            if 'scriptSig' in txin:
       -                script_sig = txin['scriptSig'].decode('hex')
       -                txinputtype.script_sig = script_sig
       -
       -            if 'sequence' in txin:
       -                sequence = txin['sequence']
       -                txinputtype.sequence = sequence
       -
       -            inputs.append(txinputtype)
       -
       -        return inputs
       -
       -    def tx_outputs(self, tx):
       -        outputs = []
       -
       -        for type, address, amount in tx.outputs:
       -            assert type == 'address'
       -            txoutputtype = types.TxOutputType()
       -            if self.wallet.is_change(address):
       -                address_path = self.wallet.address_id(address)
       -                address_n = self.get_client().expand_path(address_path)
       -                txoutputtype.address_n.extend(address_n)
       -            else:
       -                txoutputtype.address = address
       -            txoutputtype.amount = amount
       -            addrtype, hash_160 = bc_address_to_hash_160(address)
       -            if addrtype == 0:
       -                txoutputtype.script_type = types.PAYTOADDRESS
       -            elif addrtype == 5:
       -                txoutputtype.script_type = types.PAYTOSCRIPTHASH
       -            else:
       -                raise BaseException('addrtype')
       -            outputs.append(txoutputtype)
       -
       -        return outputs
       -
       -    def electrum_tx_to_txtype(self, tx):
       -        t = types.TransactionType()
       -        d = deserialize(tx.raw)
       -        t.version = d['version']
       -        t.lock_time = d['lockTime']
       -        inputs = self.tx_inputs(tx)
       -        t.inputs.extend(inputs)
       -        for vout in d['outputs']:
       -            o = t.bin_outputs.add()
       -            o.amount = vout['value']
       -            o.script_pubkey = vout['scriptPubKey'].decode('hex')
       -        return t
       -
       -    def get_tx(self, tx_hash):
       -        tx = self.prev_tx[tx_hash]
       -        tx.deserialize()
       -        return self.electrum_tx_to_txtype(tx)
       -
        if TREZOR:
            class QtGuiTrezorClient(ProtocolMixin, GuiMixin, BaseClient):
                protocol = proto