def prepare_transfer_tx(hw_session: HwSessionInfo, utxos_to_spend: List[dict], dest_addresses: List[Tuple[str, int, str]], tx_fee):
    """
    Creates a signed transaction.
    :param hw_session:
    :param utxos_to_spend: list of utxos to send
    :param dest_address: destination (Dash) address
    :param tx_fee: transaction fee
    :return: tuple (serialized tx, total transaction amount in satoshis)
    """

    insight_network = 'insight_dash'
    if hw_session.app_config.is_testnet():
        insight_network += '_testnet'
    dash_network = hw_session.app_config.dash_network

    tx_api = MyTxApiInsight(insight_network, '', hw_session.zyrkd_intf, hw_session.app_config.cache_dir)
    client = hw_session.hw_client
    client.set_tx_api(tx_api)
    inputs = []
    outputs = []
    inputs_amount = 0
    for utxo_index, utxo in enumerate(utxos_to_spend):
        if not utxo.get('bip32_path', None):
            raise Exception('No BIP32 path for UTXO ' + utxo['txid'])
        address_n = client.expand_path(clean_bip32_path(utxo['bip32_path']))
        it = proto_types.TxInputType(address_n=address_n, prev_hash=binascii.unhexlify(utxo['txid']),
                                     prev_index=utxo['outputIndex'])
        inputs.append(it)
        inputs_amount += utxo['satoshis']

    outputs_amount = 0
    for addr, amount, bip32_path in dest_addresses:
        outputs_amount += amount
        if addr[0] in dash_utils.get_chain_params(dash_network).B58_PREFIXES_SCRIPT_ADDRESS:
            stype = proto_types.PAYTOSCRIPTHASH
            logging.debug('Transaction type: PAYTOSCRIPTHASH' + str(stype))
        elif addr[0] in dash_utils.get_chain_params(dash_network).B58_PREFIXES_PUBKEY_ADDRESS:
            stype = proto_types.PAYTOADDRESS
            logging.debug('Transaction type: PAYTOADDRESS ' + str(stype))
        else:
            raise Exception('Invalid prefix of the destination address.')
        if bip32_path:
            address_n = client.expand_path(bip32_path)
        else:
            address_n = None

        ot = proto_types.TxOutputType(
            address=addr if address_n is None else None,
            address_n=address_n,
            amount=amount,
            script_type=stype
        )
        outputs.append(ot)

    if outputs_amount + tx_fee != inputs_amount:
        raise Exception('Transaction validation failure: inputs + fee != outputs')

    signed = client.sign_tx(hw_session.app_config.hw_coin_name, inputs, outputs)
    logging.info('Signed transaction')
    return signed[1], inputs_amount
示例#2
0
def sign_message(hw_session: HwSessionInfo, bip32path, message):
    client = hw_session.hw_client
    address_n = client.expand_path(clean_bip32_path(bip32path))
    try:
        return client.sign_message(hw_session.app_config.hw_coin_name, address_n, message)
    except CallException as e:
        if e.args and len(e.args) >= 2 and e.args[1].lower().find('cancelled') >= 0:
            raise CancelException('Cancelled')
        else:
            raise
示例#3
0
def sign_message(hw_client, hw_coin_name: str, bip32path: str, message: str):
    address_n = hw_client.expand_path(clean_bip32_path(bip32path))
    try:
        return hw_client.sign_message(hw_coin_name, address_n, message)
    except CallException as e:
        if e.args and len(
                e.args) >= 2 and e.args[1].lower().find('cancelled') >= 0:
            raise CancelException('Cancelled')
        else:
            raise
示例#4
0
def get_address_and_pubkey(client, bip32_path, show_display=False):
    bip32_path = clean_bip32_path(bip32_path)
    bip32_path.strip()
    if bip32_path.lower().find('m/') >= 0:
        bip32_path = bip32_path[2:]

    nodedata = client.getWalletPublicKey(bip32_path, showOnScreen=show_display)
    return {
        'address': nodedata.get('address').decode('utf-8'),
        'publicKey': compress_public_key(nodedata.get('publicKey'))
    }
示例#5
0
def get_address_and_pubkey(hw_session: HWSessionBase,
                           bip32_path,
                           show_display=False):
    bip32_path = clean_bip32_path(bip32_path)
    bip32_path.strip()
    if bip32_path.lower().find('m/') >= 0:
        bip32_path = bip32_path[2:]

    nodedata = hw_session.hw_client.getWalletPublicKey(
        bip32_path, showOnScreen=show_display)
    addr = _ledger_extract_address(nodedata.get('address'))

    return {
        'address': addr,
        'publicKey': compress_public_key(nodedata.get('publicKey'))
    }
def prepare_transfer_tx(main_ui, utxos_to_spend, dest_address, tx_fee):
    """
    Creates a signed transaction.
    :param main_ui: Main window for configuration data
    :param utxos_to_spend: list of utxos to send
    :param dest_address: destination (Dash) address
    :param tx_fee: transaction fee
    :return: tuple (serialized tx, total transaction amount in satoshis)
    """
    tx_api = MyTxApiInsight('insight_dash', None, main_ui.dashd_intf,
                            main_ui.config.cache_dir)
    client = main_ui.hw_client
    client.set_tx_api(tx_api)
    inputs = []
    outputs = []
    amt = 0
    for utxo in utxos_to_spend:
        if not utxo.get('bip32_path', None):
            raise Exception('No BIP32 path for UTXO ' + utxo['txid'])
        address_n = client.expand_path(clean_bip32_path(utxo['bip32_path']))
        it = proto_types.TxInputType(address_n=address_n,
                                     prev_hash=binascii.unhexlify(
                                         utxo['txid']),
                                     prev_index=utxo['outputIndex'])
        inputs.append(it)
        amt += utxo['satoshis']
    amt -= tx_fee
    amt = int(amt)

    # check if dest_address is a Dash address or a script address and then set appropriate script_type
    # https://github.com/dashpay/dash/blob/master/src/chainparams.cpp#L140
    if dest_address.startswith('7'):
        stype = proto_types.PAYTOSCRIPTHASH
    else:
        stype = proto_types.PAYTOADDRESS

    ot = proto_types.TxOutputType(address=dest_address,
                                  amount=amt,
                                  script_type=stype)
    outputs.append(ot)
    signed = client.sign_tx('Dash', inputs, outputs)
    return signed[1], amt
示例#7
0
def get_xpub(client, bip32_path):
    bip32_path = clean_bip32_path(bip32_path)
    bip32_path.strip()
    if bip32_path.lower().find('m/') >= 0:
        bip32_path = bip32_path[2:]
    path_n = bip32_path_string_to_n(bip32_path)
    parent_bip32_path = bip32_path_n_to_string(path_n[:-1])
    depth = len(path_n)
    index = path_n[-1]

    nodedata = client.getWalletPublicKey(bip32_path)
    pubkey = compress(nodedata.get('publicKey'))
    chaincode = nodedata.get('chainCode')

    parent_nodedata = client.getWalletPublicKey(parent_bip32_path)
    parent_pubkey = compress(parent_nodedata['publicKey'])
    parent_fingerprint = bin_hash160(parent_pubkey)[:4]

    xpub_raw = bytes.fromhex('0488b21e') + depth.to_bytes(1, 'big') + parent_fingerprint + index.to_bytes(4, 'big') + \
           chaincode + pubkey
    xpub = Base58.check_encode(xpub_raw)

    return xpub
示例#8
0
def sign_tx(hw_session: HwSessionInfo,
            utxos_to_spend: List[wallet_common.UtxoType],
            tx_outputs: List[wallet_common.TxOutputType], tx_fee):
    client = hw_session.hw_client
    rawtransactions = {}
    decodedtransactions = {}

    # Each of the UTXOs will become an input in the new transaction. For each of those inputs, create
    # a Ledger's 'trusted input', that will be used by the the device to sign a transaction.
    trusted_inputs = []

    # arg_inputs: list of dicts
    #  {
    #    'locking_script': <Locking script of the UTXO used as an input. Used in the process of signing
    #                       transaction.>,
    #    'outputIndex': <index of the UTXO within the previus transaction>,
    #    'txid': <hash of the previus transaction>,
    #    'bip32_path': <BIP32 path of the HW key controlling UTXO's destination>,
    #    'pubkey': <Public key obtained from the HW using the bip32_path.>
    #    'signature' <Signature obtained as a result of processing the input. It will be used as a part of the
    #               unlocking script.>
    #  }
    #  Why do we need a locking script of the previous transaction? When hashing a new transaction before creating its
    #  signature, all placeholders for input's unlocking script has to be filled with locking script of the
    #  corresponding UTXO. Look here for the details:
    #    https://klmoney.wordpress.com/bitcoin-dissecting-transactions-part-2-building-a-transaction-by-hand)
    arg_inputs = []

    # A dictionary mapping bip32 path to a pubkeys obtained from the Ledger device - used to avoid
    # reading it multiple times for the same bip32 path
    bip32_to_address = {}

    # read previous transactins
    for utxo in utxos_to_spend:
        if utxo.txid not in rawtransactions:
            tx = hw_session.crownd_intf.getrawtransaction(utxo.txid,
                                                          1,
                                                          skip_cache=False)
            if tx and tx.get('hex'):
                tx_raw = tx.get('hex')
            else:
                tx_raw = hw_session.crownd_intf.getrawtransaction(
                    utxo.txid, 0, skip_cache=False)

            if tx_raw:
                rawtransactions[utxo.txid] = tx_raw
            decodedtransactions[utxo.txid] = tx

    amount = 0
    starting = True
    for idx, utxo in enumerate(utxos_to_spend):
        amount += utxo.satoshis

        raw_tx = rawtransactions.get(utxo.txid)
        if not raw_tx:
            raise Exception("Can't find raw transaction for txid: " +
                            utxo.txid)
        else:
            raw_tx = bytearray.fromhex(raw_tx)

        # parse the raw transaction, so that we can extract the UTXO locking script we refer to
        prev_transaction = bitcoinTransaction(raw_tx)

        data = decodedtransactions[utxo.txid]
        dip2_type = data.get("type", 0)
        if data['version'] == 3 and dip2_type != 0:
            # It's a DIP2 special TX with payload

            if "extraPayloadSize" not in data or "extraPayload" not in data:
                raise ValueError("Payload data missing in DIP2 transaction")

            if data["extraPayloadSize"] * 2 != len(data["extraPayload"]):
                raise ValueError(
                    "extra_data_len (%d) does not match calculated length (%d)"
                    %
                    (data["extraPayloadSize"], len(data["extraPayload"]) * 2))
            prev_transaction.extra_data = crown_utils.num_to_varint(
                data["extraPayloadSize"]) + bytes.fromhex(data["extraPayload"])
        else:
            prev_transaction.extra_data = bytes()

        utxo_tx_index = utxo.output_index
        if utxo_tx_index < 0 or utxo_tx_index > len(prev_transaction.outputs):
            raise Exception('Incorrent value of outputIndex for UTXO %s' %
                            str(idx))

        trusted_input = client.getTrustedInput(prev_transaction, utxo_tx_index)
        trusted_inputs.append(trusted_input)

        bip32_path = utxo.bip32_path
        bip32_path = clean_bip32_path(bip32_path)
        pubkey = bip32_to_address.get(bip32_path)
        if not pubkey:
            pubkey = compress_public_key(
                client.getWalletPublicKey(bip32_path)['publicKey'])
            bip32_to_address[bip32_path] = pubkey
        pubkey_hash = bitcoin.bin_hash160(pubkey)

        # verify if the public key hash of the wallet's bip32 path is the same as specified in the UTXO locking script
        # if they differ, signature and public key we produce and are going to include in the unlocking script won't
        # match the locking script conditions - transaction will be rejected by the network
        pubkey_hash_from_script = extract_pkh_from_locking_script(
            prev_transaction.outputs[utxo_tx_index].script)
        if pubkey_hash != pubkey_hash_from_script:
            logging.error(
                "Error: different public key hashes for the BIP32 path %s (UTXO %s) and the UTXO locking "
                "script. Your signed transaction will not be validated by the network."
                % (bip32_path, str(idx)))

        arg_inputs.append({
            'locking_script':
            prev_transaction.outputs[utxo.output_index].script,
            'pubkey':
            pubkey,
            'bip32_path':
            bip32_path,
            'outputIndex':
            utxo.output_index,
            'txid':
            utxo.txid
        })

    amount -= int(tx_fee)
    amount = int(amount)

    new_transaction = bitcoinTransaction(
    )  # new transaction object to be used for serialization at the last stage
    new_transaction.version = bytearray([0x01, 0x00, 0x00, 0x00])
    for out in tx_outputs:
        output = bitcoinOutput()
        output.script = compose_tx_locking_script(
            out.address, hw_session.app_config.crown_network)
        output.amount = int.to_bytes(out.satoshis, 8, byteorder='little')
        new_transaction.outputs.append(output)

    # join all outputs - will be used by Ledger for sigining transaction
    all_outputs_raw = new_transaction.serializeOutputs()

    # sign all inputs on Ledger and add inputs in the new_transaction object for serialization
    for idx, new_input in enumerate(arg_inputs):

        client.startUntrustedTransaction(starting, idx, trusted_inputs,
                                         new_input['locking_script'])
        client.finalizeInputFull(all_outputs_raw)
        sig = client.untrustedHashSign(new_input['bip32_path'], lockTime=0)
        new_input['signature'] = sig

        input = bitcoinInput()
        input.prevOut = bytearray.fromhex(new_input['txid'])[::-1] + \
                        int.to_bytes(new_input['outputIndex'], 4, byteorder='little')
        input.script = bytearray([len(sig)]) + sig + bytearray(
            [0x21]) + new_input['pubkey']
        input.sequence = bytearray([0xFF, 0xFF, 0xFF, 0xFF])
        new_transaction.inputs.append(input)

        starting = False

    new_transaction.lockTime = bytearray([0, 0, 0, 0])

    tx_raw = bytearray(new_transaction.serialize())
    return tx_raw, amount
示例#9
0
def sign_message(hw_session: HwSessionInfo, bip32_path, message):

    client = hw_session.hw_client
    # Ledger doesn't accept characters other that ascii printable:
    # https://ledgerhq.github.io/btchip-doc/bitcoin-technical.html#_sign_message
    message = message.encode('ascii', 'ignore')
    bip32_path = clean_bip32_path(bip32_path)

    ok = False
    for i in range(1, 4):
        info = client.signMessagePrepare(bip32_path, message)
        if info['confirmationNeeded'] and info['confirmationType'] == 34:
            if i == 1 or \
                WndUtils.queryDlg('Another application (such as Ledger Wallet Bitcoin app) has probably taken over '
                     'the communication with the Ledger device.'
                     '\n\nTo continue, close that application and click the <b>Retry</b> button.'
                     '\nTo cancel, click the <b>Abort</b> button',
                 buttons=QMessageBox.Retry | QMessageBox.Abort,
                 default_button=QMessageBox.Retry, icon=QMessageBox.Warning) == QMessageBox.Retry:

                # we need to reconnect the device; first, we'll try to reconnect to HW without closing the intefering
                # application; it it doesn't help we'll display a message requesting the user to close the app
                hw_session.hw_disconnect()
                if hw_session.hw_connect():
                    client = hw_session.hw_client
                else:
                    raise Exception('Hardware wallet reconnect error.')
            else:
                break
        else:
            ok = True
            break

    if not ok:
        raise CancelException('Cancelled')

    try:
        signature = client.signMessageSign()
    except Exception as e:
        logging.exception('Exception while signing message with Ledger Nano S')
        raise Exception(
            'Exception while signing message with Ledger Nano S. Details: ' +
            str(e))

    try:
        pubkey = client.getWalletPublicKey(bip32_path)
    except Exception as e:
        logging.exception(
            'Could not get public key for BIP32 path from Ledger Nano S')
        raise Exception(
            'Could not get public key for BIP32 path from Ledger Nano S. Details: '
            + str(e))

    if len(signature) > 4:
        r_length = signature[3]
        r = signature[4:4 + r_length]
        if len(signature) > 4 + r_length + 1:
            s_length = signature[4 + r_length + 1]
            if len(signature) > 4 + r_length + 2:
                s = signature[4 + r_length + 2:]
                if r_length == 33:
                    r = r[1:]
                if s_length == 33:
                    s = s[1:]
            else:
                logging.error(
                    'client.signMessageSign() returned invalid response (code 3): '
                    + signature.hex())
                raise Exception('Invalid signature returned (code 3).')
        else:
            logging.error(
                'client.signMessageSign() returned invalid response (code 2): '
                + signature.hex())
            raise Exception('Invalid signature returned (code 2).')
    else:
        logging.error(
            'client.signMessageSign() returned invalid response (code 1): ' +
            signature.hex())
        raise Exception('Invalid signature returned (code 1).')

    return MessageSignature(
        pubkey.get('address').decode('ascii'),
        bytes(chr(27 + 4 + (signature[0] & 0x01)), "utf-8") + r + s)
def sign_message(hw_session: HwSessionInfo, bip32path, message):
    client = hw_session.hw_client
    address_n = client.expand_path(clean_bip32_path(bip32path))
    return client.sign_message(hw_session.app_config.hw_coin_name, address_n, message)
示例#11
0
def prepare_transfer_tx(main_ui, utxos_to_spend, dest_address, tx_fee,
                        rawtransactions):
    client = main_ui.hw_client

    # Each of the UTXOs will become an input in the new transaction. For each of those inputs, create
    # a Ledger's 'trusted input', that will be used by the the device to sign a transaction.
    trusted_inputs = []

    # arg_inputs: list of dicts
    #  {
    #    'locking_script': <Locking script of the UTXO used as an input. Used in the process of signing
    #                       transaction.>,
    #    'outputIndex': <index of the UTXO within the previus transaction>,
    #    'txid': <hash of the previus transaction>,
    #    'bip32_path': <BIP32 path of the HW key controlling UTXO's destination>,
    #    'pubkey': <Public key obtained from the HW using the bip32_path.>
    #    'signature' <Signature obtained as a result of processing the input. It will be used as a part of the
    #               unlocking script.>
    #  }
    #  Why do we need a locking script of the previous transaction? When hashing a new transaction before creating its
    #  signature, all placeholders for input's unlocking script has to be filled with locking script of the
    #  corresponding UTXO. Look here for the details:
    #    https://klmoney.wordpress.com/bitcoin-dissecting-transactions-part-2-building-a-transaction-by-hand)
    arg_inputs = []

    # A dictionary mapping bip32 path to a pubkeys obtained from the Ledger device - used to avoid
    # reading it multiple times for the same bip32 path
    bip32_to_address = {}

    amount = 0
    starting = True
    for idx, utxo in enumerate(utxos_to_spend):
        amount += utxo['satoshis']

        raw_tx = bytearray.fromhex(rawtransactions[utxo['txid']])
        if not raw_tx:
            raise Exception("Can't find raw transaction for txid: " +
                            rawtransactions[utxo['txid']])

        # parse the raw transaction, so that we can extract the UTXO locking script we refer to
        prev_transaction = bitcoinTransaction(raw_tx)

        utxo_tx_index = utxo['outputIndex']
        if utxo_tx_index < 0 or utxo_tx_index > len(prev_transaction.outputs):
            raise Exception('Incorrent value of outputIndex for UTXO %s' %
                            str(idx))

        trusted_input = client.getTrustedInput(prev_transaction, utxo_tx_index)
        trusted_inputs.append(trusted_input)

        bip32_path = utxo['bip32_path']
        bip32_path = clean_bip32_path(bip32_path)
        pubkey = bip32_to_address.get(bip32_path)
        if not pubkey:
            pubkey = compress_public_key(
                client.getWalletPublicKey(bip32_path)['publicKey'])
            bip32_to_address[bip32_path] = pubkey
        pubkey_hash = bitcoin.bin_hash160(pubkey)

        # verify if the public key hash of the wallet's bip32 path is the same as specified in the UTXO locking script
        # if they differ, signature and public key we produce and are going to include in the unlocking script won't
        # match the locking script conditions - transaction will be rejected by the network
        pubkey_hash_from_script = extract_pkh_from_locking_script(
            prev_transaction.outputs[utxo_tx_index].script)
        if pubkey_hash != pubkey_hash_from_script:
            logging.error(
                "Error: different public key hashes for the BIP32 path %s (UTXO %s) and the UTXO locking "
                "script. Your signed transaction will not be validated by the network."
                % (bip32_path, str(idx)))

        arg_inputs.append({
            'locking_script':
            prev_transaction.outputs[utxo['outputIndex']].script,
            'pubkey':
            pubkey,
            'bip32_path':
            bip32_path,
            'outputIndex':
            utxo['outputIndex'],
            'txid':
            utxo['txid']
        })

    amount -= int(tx_fee)
    amount = int(amount)
    arg_outputs = [{
        'address': dest_address,
        'valueSat': amount
    }]  # there will be multiple outputs soon

    new_transaction = bitcoinTransaction(
    )  # new transaction object to be used for serialization at the last stage
    new_transaction.version = bytearray([0x01, 0x00, 0x00, 0x00])
    for o in arg_outputs:
        output = bitcoinOutput()
        output.script = compose_tx_locking_script(o['address'])
        output.amount = int.to_bytes(o['valueSat'], 8, byteorder='little')
        new_transaction.outputs.append(output)

    # join all outputs - will be used by Ledger for sigining transaction
    all_outputs_raw = new_transaction.serializeOutputs()

    # sign all inputs on Ledger and add inputs in the new_transaction object for serialization
    for idx, new_input in enumerate(arg_inputs):

        client.startUntrustedTransaction(starting, idx, trusted_inputs,
                                         new_input['locking_script'])
        client.finalizeInputFull(all_outputs_raw)
        sig = client.untrustedHashSign(new_input['bip32_path'], lockTime=0)
        new_input['signature'] = sig

        input = bitcoinInput()
        input.prevOut = bytearray.fromhex(new_input['txid'])[::-1] + \
                        int.to_bytes(new_input['outputIndex'], 4, byteorder='little')
        input.script = bytearray([len(sig)]) + sig + bytearray(
            [0x21]) + new_input['pubkey']
        input.sequence = bytearray([0xFF, 0xFF, 0xFF, 0xFF])
        new_transaction.inputs.append(input)

        starting = False

    new_transaction.lockTime = bytearray([0, 0, 0, 0])

    tx_raw = bytearray(new_transaction.serialize())
    return tx_raw, amount
def sign_tx(hw_session: HwSessionInfo,
            utxos_to_spend: List[wallet_common.UtxoType],
            tx_outputs: List[wallet_common.TxOutputType], tx_fee):
    """
    Creates a signed transaction.
    :param hw_session:
    :param utxos_to_spend: list of utxos to send
    :param tx_outputs: list of transaction outputs
    :param tx_fee: transaction fee
    :return: tuple (serialized tx, total transaction amount in satoshis)
    """

    insight_network = 'insight_fix'
    if hw_session.app_config.is_testnet():
        insight_network += '_testnet'
    fix_network = hw_session.app_config.fix_network

    tx_api = MyTxApiInsight(insight_network, '', hw_session.fixd_intf,
                            hw_session.app_config.tx_cache_dir)
    client = hw_session.hw_client
    client.set_tx_api(tx_api)
    inputs = []
    outputs = []
    inputs_amount = 0
    for utxo_index, utxo in enumerate(utxos_to_spend):
        if not utxo.bip32_path:
            raise Exception('No BIP32 path for UTXO ' + utxo.txid)
        address_n = client.expand_path(clean_bip32_path(utxo.bip32_path))
        it = proto_types.TxInputType(address_n=address_n,
                                     prev_hash=binascii.unhexlify(utxo.txid),
                                     prev_index=utxo.output_index)
        inputs.append(it)
        inputs_amount += utxo.satoshis

    outputs_amount = 0
    for out in tx_outputs:
        outputs_amount += out.satoshis
        if out.address[0] in fix_utils.get_chain_params(
                fix_network).B58_PREFIXES_SCRIPT_ADDRESS:
            stype = proto_types.PAYTOSCRIPTHASH
            logging.debug('Transaction type: PAYTOSCRIPTHASH' + str(stype))
        elif out.address[0] in fix_utils.get_chain_params(
                fix_network).B58_PREFIXES_PUBKEY_ADDRESS:
            stype = proto_types.PAYTOADDRESS
            logging.debug('Transaction type: PAYTOADDRESS ' + str(stype))
        else:
            raise Exception('Invalid prefix of the destination address.')
        if out.bip32_path:
            address_n = client.expand_path(out.bip32_path)
        else:
            address_n = None

        ot = proto_types.TxOutputType(
            address=out.address if address_n is None else None,
            address_n=address_n,
            amount=out.satoshis,
            script_type=stype)
        outputs.append(ot)

    if outputs_amount + tx_fee != inputs_amount:
        raise Exception(
            'Transaction validation failure: inputs + fee != outputs')

    signed = client.sign_tx(hw_session.app_config.hw_coin_name, inputs,
                            outputs)
    logging.info('Signed transaction')
    return signed[1], inputs_amount
示例#13
0
def sign_message(main_ui, bip32path, message):
    client = main_ui.hw_client
    address_n = client.expand_path(clean_bip32_path(bip32path))
    return client.sign_message('Dash', address_n, message)