diff --git a/contrib/requirements/requirements-hw.txt b/contrib/requirements/requirements-hw.txt index a9577d084..307a6adcc 100644 --- a/contrib/requirements/requirements-hw.txt +++ b/contrib/requirements/requirements-hw.txt @@ -1,5 +1,5 @@ hidapi -trezor[hidapi]>=0.12.0 +trezor[hidapi]>=0.13.0,<0.14 safet>=0.1.5 keepkey>=6.3.1 btchip-python>=0.1.32 diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py index bba2ad57c..c6730085e 100644 --- a/electrum/plugins/trezor/clientbase.py +++ b/electrum/plugins/trezor/clientbase.py @@ -268,8 +268,8 @@ class TrezorClientBase(HardwareClientBase, Logger): # ========= UI methods ========== - def button_request(self, code): - message = self.msg or MESSAGES.get(code) or MESSAGES['default'] + def button_request(self, br): + message = self.msg or MESSAGES.get(br.code) or MESSAGES['default'] self.handler.show_message(message.format(self.device), self.client.cancel) def get_pin(self, code=None): diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index be9d7b859..0456b8975 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -30,7 +30,7 @@ try: from trezorlib.messages import ( Capability, BackupType, RecoveryDeviceType, HDNodeType, HDNodePathType, InputScriptType, OutputScriptType, MultisigRedeemScriptType, - TxInputType, TxOutputType, TxOutputBinType, TransactionType, SignTx) + TxInputType, TxOutputType, TxOutputBinType, TransactionType, AmountUnit) from trezorlib.client import PASSPHRASE_ON_DEVICE @@ -54,6 +54,7 @@ except Exception as e: Capability = _EnumMissing() BackupType = _EnumMissing() RecoveryDeviceType = _EnumMissing() + AmountUnit = _EnumMissing() PASSPHRASE_ON_DEVICE = object() @@ -117,8 +118,8 @@ class TrezorPlugin(HW_PluginBase): libraries_URL = 'https://pypi.org/project/trezor/' minimum_firmware = (1, 5, 2) keystore_class = TrezorKeyStore - minimum_library = (0, 12, 0) - maximum_library = (0, 13) + minimum_library = (0, 13, 0) + maximum_library = (0, 14) SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh') DEVICE_IDS = (TREZOR_PRODUCT_KEY,) @@ -326,6 +327,8 @@ class TrezorPlugin(HW_PluginBase): return InputScriptType.SPENDADDRESS if electrum_txin_type in ('p2sh',): return InputScriptType.SPENDMULTISIG + if electrum_txin_type in ('p2tr',): + return InputScriptType.SPENDTAPROOT raise ValueError('unexpected txin type: {}'.format(electrum_txin_type)) def get_trezor_output_script_type(self, electrum_txin_type: str): @@ -337,16 +340,32 @@ class TrezorPlugin(HW_PluginBase): return OutputScriptType.PAYTOADDRESS if electrum_txin_type in ('p2sh',): return OutputScriptType.PAYTOMULTISIG + if electrum_txin_type in ('p2tr',): + return OutputScriptType.PAYTOTAPROOT raise ValueError('unexpected txin type: {}'.format(electrum_txin_type)) + def get_trezor_amount_unit(self): + if self.config.decimal_point == 0: + return AmountUnit.SATOSHI + elif self.config.decimal_point == 2: + return AmountUnit.MICROBITCOIN + elif self.config.decimal_point == 5: + return AmountUnit.MILLIBITCOIN + else: + return AmountUnit.BITCOIN + @runs_in_hwd_thread def sign_transaction(self, keystore, tx: PartialTransaction, prev_tx): prev_tx = {bfh(txhash): self.electrum_tx_to_txtype(tx) for txhash, tx in prev_tx.items()} client = self.get_client(keystore) inputs = self.tx_inputs(tx, for_sig=True, keystore=keystore) outputs = self.tx_outputs(tx, keystore=keystore) - details = SignTx(lock_time=tx.locktime, version=tx.version) - signatures, _ = client.sign_tx(self.get_coin_name(), inputs, outputs, details=details, prev_txes=prev_tx) + signatures, _ = client.sign_tx(self.get_coin_name(), + inputs, outputs, + lock_time=tx.locktime, + version=tx.version, + amount_unit=self.get_trezor_amount_unit(), + prev_txes=prev_tx) signatures = [(bh2u(x) + '01') for x in signatures] tx.update_signatures(signatures) @@ -379,39 +398,30 @@ class TrezorPlugin(HW_PluginBase): def tx_inputs(self, tx: Transaction, *, for_sig=False, keystore: 'TrezorKeyStore' = None): inputs = [] for txin in tx.inputs(): - txinputtype = TxInputType() if txin.is_coinbase_input(): - prev_hash = b"\x00"*32 - prev_index = 0xffffffff # signed int -1 + txinputtype = TxInputType( + prev_hash=b"\x00"*32, + prev_index=0xffffffff, # signed int -1 + ) else: + txinputtype = TxInputType( + prev_hash=txin.prevout.txid, + prev_index=txin.prevout.out_idx, + ) if for_sig: assert isinstance(tx, PartialTransaction) assert isinstance(txin, PartialTxInput) assert keystore if len(txin.pubkeys) > 1: xpubs_and_deriv_suffixes = get_xpubs_and_der_suffixes_from_txinout(tx, txin) - multisig = self._make_multisig(txin.num_sig, xpubs_and_deriv_suffixes) - else: - multisig = None - script_type = self.get_trezor_input_script_type(txin.script_type) - txinputtype = TxInputType( - script_type=script_type, - multisig=multisig) + txinputtype.multisig = self._make_multisig(txin.num_sig, xpubs_and_deriv_suffixes) + txinputtype.script_type = self.get_trezor_input_script_type(txin.script_type) my_pubkey, full_path = keystore.find_my_pubkey_in_txinout(txin) if full_path: txinputtype.address_n = full_path - prev_hash = txin.prevout.txid - prev_index = txin.prevout.out_idx - - if txin.value_sats() is not None: - txinputtype.amount = txin.value_sats() - txinputtype.prev_hash = prev_hash - txinputtype.prev_index = prev_index - - if txin.script_sig is not None: - txinputtype.script_sig = txin.script_sig - + txinputtype.amount = txin.value_sats() + txinputtype.script_sig = txin.script_sig txinputtype.sequence = txin.nsequence inputs.append(txinputtype) @@ -446,15 +456,18 @@ class TrezorPlugin(HW_PluginBase): return txoutputtype def create_output_by_address(): - txoutputtype = TxOutputType() - txoutputtype.amount = txout.value if address: - txoutputtype.script_type = OutputScriptType.PAYTOADDRESS - txoutputtype.address = address + return TxOutputType( + amount=txout.value, + script_type=OutputScriptType.PAYTOADDRESS, + address=address, + ) else: - txoutputtype.script_type = OutputScriptType.PAYTOOPRETURN - txoutputtype.op_return_data = trezor_validate_op_return_output_and_get_data(txout) - return txoutputtype + return TxOutputType( + amount=txout.value, + script_type=OutputScriptType.PAYTOOPRETURN, + op_return_data=trezor_validate_op_return_output_and_get_data(txout), + ) outputs = [] has_change = False