Exemple #1
0
async def _sign_standard_tx(ctx: wire.Context, msg: CardanoSignTx,
                            keychain: seed.Keychain) -> CardanoSignedTx:
    try:
        for i in msg.inputs:
            await validate_path(ctx, keychain, i.address_n,
                                SCHEMA_ADDRESS.match(i.address_n))

        _validate_outputs(keychain, msg.outputs, msg.protocol_magic,
                          msg.network_id)
        _validate_certificates(msg.certificates, msg.protocol_magic,
                               msg.network_id)
        _validate_withdrawals(msg.withdrawals)
        _validate_metadata(msg.metadata)

        # display the transaction in UI
        await _show_standard_tx(ctx, keychain, msg)

        # sign the transaction bundle and prepare the result
        serialized_tx, tx_hash = _serialize_tx(keychain, msg)
        tx = CardanoSignedTx(serialized_tx=serialized_tx, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    return tx
Exemple #2
0
async def sign_tx(
    ctx: wire.Context, msg: CardanoSignTx, keychain: seed.Keychain
) -> CardanoSignedTx:
    try:
        if msg.fee > LOVELACE_MAX_SUPPLY:
            raise wire.ProcessError("Fee is out of range!")

        _validate_network_info(msg.network_id, msg.protocol_magic)

        for i in msg.inputs:
            await validate_path(ctx, validate_full_path, keychain, i.address_n, CURVE)

        _validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id)
        _validate_certificates(msg.certificates)
        _validate_withdrawals(msg.withdrawals)
        _validate_metadata(msg.metadata)

        # display the transaction in UI
        await _show_tx(ctx, keychain, msg)

        # sign the transaction bundle and prepare the result
        serialized_tx, tx_hash = _serialize_tx(keychain, msg)
        tx = CardanoSignedTx(serialized_tx=serialized_tx, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    return tx
Exemple #3
0
async def _sign_stake_pool_registration_tx(
    ctx: wire.Context, msg: CardanoSignTx, keychain: seed.Keychain
) -> CardanoSignedTx:
    """
    We have a separate tx signing flow for stake pool registration because it's a
    transaction where the witnessable entries (i.e. inputs, withdrawals, etc.)
    in the transaction are not supposed to be controlled by the HW wallet, which
    means the user is vulnerable to unknowingly supplying a witness for an UTXO
    or other tx entry they think is external, resulting in the co-signers
    gaining control over their funds (Something SLIP-0019 is dealing with for
    BTC but no similar standard is currently available for Cardano). Hence we
    completely forbid witnessing inputs and other entries of the transaction
    except the stake pool certificate itself and we provide a witness only to the
    user's staking key in the list of pool owners.
    """
    try:
        _validate_stake_pool_registration_tx_structure(msg)

        _ensure_no_signing_inputs(msg.inputs)
        _validate_outputs(keychain, msg.outputs, msg.protocol_magic, msg.network_id)
        _validate_certificates(msg.certificates, msg.protocol_magic, msg.network_id)
        _validate_metadata(msg.metadata)

        await _show_stake_pool_registration_tx(ctx, keychain, msg)

        # sign the transaction bundle and prepare the result
        serialized_tx, tx_hash = _serialize_tx(keychain, msg)
        tx = CardanoSignedTx(serialized_tx=serialized_tx, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    return tx
Exemple #4
0
async def sign_tx(ctx, msg):
    keychain = await seed.get_keychain(ctx)

    progress.init(msg.transactions_count, "Loading data")

    try:
        attested = len(msg.inputs) * [False]
        input_coins_sum = 0
        # request transactions
        tx_req = CardanoTxRequest()

        for index in range(msg.transactions_count):
            progress.advance()
            tx_ack = await request_transaction(ctx, tx_req, index)
            tx_hash = hashlib.blake2b(data=bytes(tx_ack.transaction),
                                      outlen=32).digest()
            tx_decoded = cbor.decode(tx_ack.transaction)
            for i, input in enumerate(msg.inputs):
                if not attested[i] and input.prev_hash == tx_hash:
                    attested[i] = True
                    outputs = tx_decoded[1]
                    amount = outputs[input.prev_index][1]
                    input_coins_sum += amount

        if not all(attested):
            raise wire.ProcessError("No tx data sent for input " +
                                    str(attested.index(False)))

        transaction = Transaction(msg.inputs, msg.outputs, keychain,
                                  msg.protocol_magic, input_coins_sum)

        # clear progress bar
        display_homescreen()

        for i in msg.inputs:
            await validate_path(ctx, validate_full_path, keychain, i.address_n,
                                CURVE)

        # sign the transaction bundle and prepare the result
        tx_body, tx_hash = transaction.serialise_tx()
        tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    # display the transaction in UI
    if not await show_tx(
            ctx,
            transaction.output_addresses,
            transaction.outgoing_coins,
            transaction.fee,
            transaction.network_name,
            transaction.inputs,
            transaction.outputs,
    ):
        raise wire.ActionCancelled("Signing cancelled")

    return tx
Exemple #5
0
async def sign_tx(ctx: wire.Context, msg: CardanoSignTx,
                  keychain: seed.Keychain) -> CardanoSignedTx:
    if msg.fee > LOVELACE_MAX_SUPPLY:
        raise wire.ProcessError("Fee is out of range!")

    validate_network_info(msg.network_id, msg.protocol_magic)

    try:
        if _has_stake_pool_registration(msg):
            cborized_tx, tx_hash = await _sign_stake_pool_registration_tx(
                ctx, msg, keychain)
        else:
            cborized_tx, tx_hash = await _sign_ordinary_tx(ctx, msg, keychain)

        signed_tx_chunks = cbor.encode_chunked(cborized_tx, MAX_TX_CHUNK_SIZE)

        for signed_tx_chunk in signed_tx_chunks:
            response = CardanoSignedTxChunk(signed_tx_chunk=signed_tx_chunk)
            await ctx.call(response, CardanoSignedTxChunkAck)

        return CardanoSignedTx(tx_hash=tx_hash, serialized_tx=None)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")
Exemple #6
0
async def sign_tx(ctx, msg):
    mnemonic = storage.get_mnemonic()
    passphrase = await seed._get_cached_passphrase(ctx)
    root_node = bip32.from_mnemonic_cardano(mnemonic, passphrase)

    progress.init(msg.transactions_count, "Loading data")

    try:
        # request transactions
        transactions = []
        tx_req = CardanoTxRequest()
        for index in range(msg.transactions_count):
            progress.advance()
            tx_ack = await request_transaction(ctx, tx_req, index)
            transactions.append(tx_ack.transaction)

        # clear progress bar
        display_homescreen()

        for i in msg.inputs:
            await validate_path(ctx, validate_full_path, path=i.address_n)

        # sign the transaction bundle and prepare the result
        transaction = Transaction(msg.inputs, msg.outputs, transactions,
                                  root_node, msg.network)
        tx_body, tx_hash = transaction.serialise_tx()
        tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    # display the transaction in UI
    if not await show_tx(
            ctx,
            transaction.output_addresses,
            transaction.outgoing_coins,
            transaction.change_derivation_paths,
            transaction.change_coins,
            transaction.fee,
            len(tx_body),
            transaction.network_name,
    ):
        raise wire.ActionCancelled("Signing cancelled")

    return tx
Exemple #7
0
async def sign_tx(ctx, msg):
    keychain = await seed.get_keychain(ctx)

    progress.init(msg.transactions_count, "Loading data")

    try:
        # request transactions
        transactions = []
        tx_req = CardanoTxRequest()
        for index in range(msg.transactions_count):
            progress.advance()
            tx_ack = await request_transaction(ctx, tx_req, index)
            transactions.append(tx_ack.transaction)

        # clear progress bar
        display_homescreen()

        for i in msg.inputs:
            await validate_path(ctx, validate_full_path, keychain, i.address_n,
                                CURVE)

        # sign the transaction bundle and prepare the result
        transaction = Transaction(msg.inputs, msg.outputs, transactions,
                                  keychain, msg.protocol_magic)
        tx_body, tx_hash = transaction.serialise_tx()
        tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash)

    except ValueError as e:
        if __debug__:
            log.exception(__name__, e)
        raise wire.ProcessError("Signing failed")

    # display the transaction in UI
    if not await show_tx(
            ctx,
            transaction.output_addresses,
            transaction.outgoing_coins,
            transaction.fee,
            transaction.network_name,
            transaction.inputs,
            transaction.outputs,
    ):
        raise wire.ActionCancelled("Signing cancelled")

    return tx