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
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
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
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
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")
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
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