URI: 
       tledger: support sending to OP_RETURN outputs - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 6b8c447eb90a0a37f7271681e98f319c8178592a
   DIR parent 02baae10d75f5ea95eb3096b17556a2d371f0113
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Tue, 17 Dec 2019 21:10:14 +0100
       
       ledger: support sending to OP_RETURN outputs
       
       closes #5849
       
       based on:
       https://github.com/Electron-Cash/Electron-Cash/commit/ca9b432ff016f734318b13c719370c22e1c28b98
       https://github.com/Electron-Cash/Electron-Cash/commit/7bb27eff849e135af486e7611483a54005c797c8
       
       Diffstat:
         M electrum/plugins/hw_wallet/plugin.… |      12 +++++++++++-
         M electrum/plugins/ledger/ledger.py   |      20 +++++++++++++++-----
       
       2 files changed, 26 insertions(+), 6 deletions(-)
       ---
   DIR diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py
       t@@ -188,13 +188,23 @@ def is_any_tx_output_on_change_branch(tx: PartialTransaction) -> bool:
        
        
        def trezor_validate_op_return_output_and_get_data(output: TxOutput) -> bytes:
       +    validate_op_return_output(output)
            script = output.scriptpubkey
            if not (script[0] == opcodes.OP_RETURN and
                    script[1] == len(script) - 2 and script[1] <= 75):
                raise UserFacingException(_("Only OP_RETURN scripts, with one constant push, are supported."))
       +    return script[2:]
       +
       +
       +def validate_op_return_output(output: TxOutput, *, max_size: int = None) -> None:
       +    script = output.scriptpubkey
       +    if script[0] != opcodes.OP_RETURN:
       +        raise UserFacingException(_("Only OP_RETURN scripts are supported."))
       +    if max_size is not None and len(script) > max_size:
       +        raise UserFacingException(_("OP_RETURN payload too large." + "\n"
       +                                  + f"(scriptpubkey size {len(script)} > {max_size})"))
            if output.value != 0:
                raise UserFacingException(_("Amount for OP_RETURN output must be zero."))
       -    return script[2:]
        
        
        def get_xpubs_and_der_suffixes_from_txinout(tx: PartialTransaction,
   DIR diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
       t@@ -2,6 +2,7 @@ from struct import pack, unpack
        import hashlib
        import sys
        import traceback
       +from typing import Optional
        
        from electrum import ecc
        from electrum import bip32
       t@@ -17,7 +18,7 @@ from electrum.base_wizard import ScriptTypeNotSupported
        from electrum.logging import get_logger
        
        from ..hw_wallet import HW_PluginBase, HardwareClientBase
       -from ..hw_wallet.plugin import is_any_tx_output_on_change_branch
       +from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, validate_op_return_output
        
        
        _logger = get_logger(__name__)
       t@@ -61,9 +62,10 @@ def test_pin_unlocked(func):
        
        
        class Ledger_Client(HardwareClientBase):
       -    def __init__(self, hidDevice):
       +    def __init__(self, hidDevice, *, is_hw1: bool = False):
                self.dongleObject = btchip(hidDevice)
                self.preflightDone = False
       +        self._is_hw1 = is_hw1
        
            def is_pairable(self):
                return True
       t@@ -80,6 +82,9 @@ class Ledger_Client(HardwareClientBase):
            def label(self):
                return ""
        
       +    def is_hw1(self) -> bool:
       +        return self._is_hw1
       +
            def has_usable_connection_with_device(self):
                try:
                    self.dongleObject.getFirmwareVersion()
       t@@ -233,7 +238,7 @@ class Ledger_KeyStore(Hardware_KeyStore):
            def get_client(self):
                return self.plugin.get_client(self).dongleObject
        
       -    def get_client_electrum(self):
       +    def get_client_electrum(self) -> Optional[Ledger_Client]:
                return self.plugin.get_client(self)
        
            def give_error(self, message, clear_client = False):
       t@@ -382,7 +387,11 @@ class Ledger_KeyStore(Hardware_KeyStore):
                    has_change = False
                    any_output_on_change_branch = is_any_tx_output_on_change_branch(tx)
                    for txout in tx.outputs():
       -                assert txout.address
       +                if not txout.address:
       +                    if self.get_client_electrum().is_hw1():
       +                        self.give_error(_("Only address outputs are supported by {}").format(self.device))
       +                    # note: max_size based on https://github.com/LedgerHQ/ledger-app-btc/commit/3a78dee9c0484821df58975803e40d58fbfc2c38#diff-c61ccd96a6d8b54d48f54a3bc4dfa7e2R26
       +                    validate_op_return_output(txout, max_size=190)
                        if txout.is_mine and len(tx.outputs()) > 1 \
                                and not has_change:
                            # prioritise hiding outputs on the 'change' branch from user
       t@@ -570,7 +579,8 @@ class LedgerPlugin(HW_PluginBase):
        
                client = self.get_btchip_device(device)
                if client is not None:
       -            client = Ledger_Client(client)
       +            is_hw1 = device.product_key[0] == 0x2581
       +            client = Ledger_Client(client, is_hw1=is_hw1)
                return client
        
            def setup_device(self, device_info, wizard, purpose):