예제 #1
0
async def _process_minting(
        ctx: wire.Context,
        minting_dict: HashBuilderDict[bytes, HashBuilderDict]) -> None:
    """Read, validate and serialize the asset groups of token minting."""
    token_minting: CardanoTxMint = await ctx.call(CardanoTxItemAck(),
                                                  CardanoTxMint)

    await show_warning_tx_contains_mint(ctx)

    # until the CIP with canonical CBOR is finalized storing the seen_policy_ids is the only way we can check for
    # duplicate policy_ids
    seen_policy_ids: set[bytes] = set()
    for _ in range(token_minting.asset_groups_count):
        asset_group: CardanoAssetGroup = await ctx.call(
            CardanoTxItemAck(), CardanoAssetGroup)
        _validate_asset_group(asset_group, seen_policy_ids, is_mint=True)
        seen_policy_ids.add(asset_group.policy_id)

        tokens: HashBuilderDict[bytes, int] = HashBuilderDict(
            asset_group.tokens_count)
        with minting_dict.add(asset_group.policy_id, tokens):
            await _process_minting_tokens(
                ctx,
                tokens,
                asset_group.policy_id,
                asset_group.tokens_count,
            )
예제 #2
0
async def _process_asset_groups(
    ctx: wire.Context,
    asset_groups_dict: HashBuilderDict[bytes, HashBuilderDict[bytes, int]],
    asset_groups_count: int,
    should_show_tokens: bool,
) -> None:
    """Read, validate and serialize the asset groups of an output."""
    # until the CIP with canonical CBOR is finalized storing the seen_policy_ids is the only way we can check for
    # duplicate policy_ids
    seen_policy_ids: set[bytes] = set()
    for _ in range(asset_groups_count):
        asset_group: CardanoAssetGroup = await ctx.call(
            CardanoTxItemAck(), CardanoAssetGroup)
        _validate_asset_group(asset_group, seen_policy_ids)
        seen_policy_ids.add(asset_group.policy_id)

        tokens: HashBuilderDict[bytes, int] = HashBuilderDict(
            asset_group.tokens_count)
        with asset_groups_dict.add(asset_group.policy_id, tokens):
            await _process_tokens(
                ctx,
                tokens,
                asset_group.policy_id,
                asset_group.tokens_count,
                should_show_tokens,
            )
예제 #3
0
async def _process_auxiliary_data(
    ctx: wire.Context,
    keychain: seed.Keychain,
    tx_body_builder_dict: HashBuilderDict,
    protocol_magic: int,
    network_id: int,
) -> None:
    """Read, validate, confirm and serialize the auxiliary data."""
    auxiliary_data: CardanoTxAuxiliaryData = await ctx.call(
        CardanoTxItemAck(), CardanoTxAuxiliaryData)
    validate_auxiliary_data(auxiliary_data)

    (
        auxiliary_data_hash,
        auxiliary_data_supplement,
    ) = get_auxiliary_data_hash_and_supplement(keychain, auxiliary_data,
                                               protocol_magic, network_id)

    await show_auxiliary_data(
        ctx,
        keychain,
        auxiliary_data_hash,
        auxiliary_data.catalyst_registration_parameters,
        protocol_magic,
        network_id,
    )

    tx_body_builder_dict.add(TX_BODY_KEY_AUXILIARY_DATA, auxiliary_data_hash)

    await ctx.call(auxiliary_data_supplement, CardanoTxHostAck)
예제 #4
0
async def _process_withdrawals(
    ctx: wire.Context,
    keychain: seed.Keychain,
    withdrawals_dict: HashBuilderDict[bytes, int],
    withdrawals_count: int,
    signing_mode: CardanoTxSigningMode,
    protocol_magic: int,
    network_id: int,
    account_path_checker: AccountPathChecker,
) -> None:
    """Read, validate, confirm and serialize the withdrawals."""
    if withdrawals_count == 0:
        return

    for _ in range(withdrawals_count):
        withdrawal: CardanoTxWithdrawal = await ctx.call(
            CardanoTxItemAck(), CardanoTxWithdrawal)
        _validate_withdrawal(
            withdrawal,
            signing_mode,
            account_path_checker,
        )
        reward_address_bytes = _derive_withdrawal_reward_address_bytes(
            keychain, withdrawal, protocol_magic, network_id)

        await confirm_withdrawal(ctx, withdrawal, reward_address_bytes,
                                 network_id)

        withdrawals_dict.add(reward_address_bytes, withdrawal.amount)
예제 #5
0
async def _process_witness_requests(
    ctx: wire.Context,
    keychain: seed.Keychain,
    tx_hash: bytes,
    witness_requests_count: int,
    signing_mode: CardanoTxSigningMode,
    transaction_has_token_minting: bool,
    account_path_checker: AccountPathChecker,
) -> CardanoTxResponseType:
    response: CardanoTxResponseType = CardanoTxItemAck()

    for _ in range(witness_requests_count):
        witness_request = await ctx.call(response, CardanoTxWitnessRequest)
        _validate_witness_request(
            witness_request,
            signing_mode,
            transaction_has_token_minting,
            account_path_checker,
        )
        path = witness_request.path
        await _show_witness_request(ctx, path, signing_mode)
        if is_byron_path(path):
            response = _get_byron_witness(keychain, path, tx_hash)
        else:
            response = _get_shelley_witness(keychain, path, tx_hash)

    return response
예제 #6
0
async def _process_certificates(
    ctx: wire.Context,
    keychain: seed.Keychain,
    certificates_list: HashBuilderList,
    certificates_count: int,
    signing_mode: CardanoTxSigningMode,
    protocol_magic: int,
    network_id: int,
    account_path_checker: AccountPathChecker,
) -> None:
    """Read, validate, confirm and serialize the certificates."""
    if certificates_count == 0:
        return

    for _ in range(certificates_count):
        certificate: CardanoTxCertificate = await ctx.call(
            CardanoTxItemAck(), CardanoTxCertificate)
        validate_certificate(certificate, signing_mode, protocol_magic,
                             network_id, account_path_checker)
        await _show_certificate(ctx, certificate, signing_mode)

        if certificate.type == CardanoCertificateType.STAKE_POOL_REGISTRATION:
            pool_parameters = certificate.pool_parameters
            assert pool_parameters is not None  # validate_certificate

            pool_items_list: HashBuilderList = HashBuilderList(
                POOL_REGISTRATION_CERTIFICATE_ITEMS_COUNT)
            with certificates_list.append(pool_items_list):
                for item in cborize_initial_pool_registration_certificate_fields(
                        certificate):
                    pool_items_list.append(item)

                pool_owners_list: HashBuilderList[bytes] = HashBuilderList(
                    pool_parameters.owners_count)
                with pool_items_list.append(pool_owners_list):
                    await _process_pool_owners(
                        ctx,
                        keychain,
                        pool_owners_list,
                        pool_parameters.owners_count,
                        protocol_magic,
                        network_id,
                        account_path_checker,
                    )

                relays_list: HashBuilderList[
                    cbor.CborSequence] = HashBuilderList(
                        pool_parameters.relays_count)
                with pool_items_list.append(relays_list):
                    await _process_pool_relays(ctx, relays_list,
                                               pool_parameters.relays_count)

                pool_items_list.append(
                    cborize_pool_metadata(pool_parameters.metadata))
        else:
            certificates_list.append(cborize_certificate(
                keychain, certificate))
예제 #7
0
async def _process_inputs(
    ctx: wire.Context,
    inputs_list: HashBuilderList[tuple[bytes, int]],
    inputs_count: int,
) -> None:
    """Read, validate and serialize the inputs."""
    for _ in range(inputs_count):
        input: CardanoTxInput = await ctx.call(CardanoTxItemAck(), CardanoTxInput)
        inputs_list.append((input.prev_hash, input.prev_index))
예제 #8
0
async def _process_pool_relays(
    ctx: wire.Context,
    relays_list: HashBuilderList[cbor.CborSequence],
    relays_count: int,
) -> None:
    for _ in range(relays_count):
        relay: CardanoPoolRelayParameters = await ctx.call(
            CardanoTxItemAck(), CardanoPoolRelayParameters)
        validate_pool_relay(relay)
        relays_list.append(cborize_pool_relay(relay))
예제 #9
0
async def _process_collateral_inputs(
    ctx: wire.Context,
    collateral_inputs_list: HashBuilderList[tuple[bytes, int]],
    collateral_inputs_count: int,
) -> None:
    """Read, validate, show and serialize the collateral inputs."""
    for _ in range(collateral_inputs_count):
        collateral_input: CardanoTxCollateralInput = await ctx.call(
            CardanoTxItemAck(), CardanoTxCollateralInput)
        _validate_collateral_input(collateral_input)
        await confirm_collateral_input(ctx, collateral_input)

        collateral_inputs_list.append(
            (collateral_input.prev_hash, collateral_input.prev_index))
예제 #10
0
async def _process_minting_tokens(
    ctx: wire.Context,
    tokens: HashBuilderDict[bytes, int],
    policy_id: bytes,
    tokens_count: int,
) -> None:
    """Read, validate, confirm and serialize the tokens of an asset group."""
    for _ in range(tokens_count):
        token: CardanoToken = await ctx.call(CardanoTxItemAck(), CardanoToken)
        _validate_token(token, is_mint=True)
        await confirm_token_minting(ctx, policy_id, token)

        assert token.mint_amount is not None  # _validate_token
        tokens.add(token.asset_name_bytes, token.mint_amount)
예제 #11
0
async def _process_minting(
        ctx: wire.Context,
        minting_dict: HashBuilderDict[bytes, HashBuilderDict]) -> None:
    """Read, validate and serialize the asset groups of token minting."""
    token_minting: CardanoTxMint = await ctx.call(CardanoTxItemAck(),
                                                  CardanoTxMint)

    await show_warning_tx_contains_mint(ctx)

    for _ in range(token_minting.asset_groups_count):
        asset_group: CardanoAssetGroup = await ctx.call(
            CardanoTxItemAck(), CardanoAssetGroup)
        _validate_asset_group(asset_group, is_mint=True)

        tokens: HashBuilderDict[bytes, int] = HashBuilderDict(
            asset_group.tokens_count, INVALID_TOKEN_BUNDLE_MINT)
        with minting_dict.add(asset_group.policy_id, tokens):
            await _process_minting_tokens(
                ctx,
                tokens,
                asset_group.policy_id,
                asset_group.tokens_count,
            )
예제 #12
0
async def _process_inputs(
    ctx: wire.Context,
    inputs_list: HashBuilderList[tuple[bytes, int]],
    inputs_count: int,
    signing_mode: CardanoTxSigningMode,
) -> None:
    """Read, validate and serialize the inputs."""
    for _ in range(inputs_count):
        input: CardanoTxInput = await ctx.call(CardanoTxItemAck(),
                                               CardanoTxInput)
        _validate_input(input)
        if signing_mode == CardanoTxSigningMode.PLUTUS_TRANSACTION:
            await confirm_input(ctx, input)

        inputs_list.append((input.prev_hash, input.prev_index))
예제 #13
0
async def _process_tokens(
    ctx: wire.Context,
    tokens_dict: HashBuilderDict[bytes, int],
    policy_id: bytes,
    tokens_count: int,
    should_show_tokens: bool,
) -> None:
    """Read, validate, confirm and serialize the tokens of an asset group."""
    for _ in range(tokens_count):
        token: CardanoToken = await ctx.call(CardanoTxItemAck(), CardanoToken)
        _validate_token(token)
        if should_show_tokens:
            await confirm_sending_token(ctx, policy_id, token)

        assert token.amount is not None  # _validate_token
        tokens_dict.add(token.asset_name_bytes, token.amount)
예제 #14
0
async def _process_required_signers(
    ctx: wire.Context,
    keychain: seed.Keychain,
    required_signers_list: HashBuilderList[bytes],
    required_signers_count: int,
) -> None:
    """Read, validate, show and serialize the required signers."""
    for _ in range(required_signers_count):
        required_signer: CardanoTxRequiredSigner = await ctx.call(
            CardanoTxItemAck(), CardanoTxRequiredSigner)
        _validate_required_signer(required_signer)
        await confirm_required_signer(ctx, required_signer)

        key_hash = required_signer.key_hash or get_public_key_hash(
            keychain, required_signer.key_path)

        required_signers_list.append(key_hash)
예제 #15
0
async def _process_minting_tokens(
    ctx: wire.Context,
    tokens: HashBuilderDict[bytes, int],
    policy_id: bytes,
    tokens_count: int,
) -> None:
    """Read, validate, confirm and serialize the tokens of an asset group."""
    # until the CIP with canonical CBOR is finalized storing the seen_asset_name_bytes is the only way we can check for
    # duplicate tokens
    seen_asset_name_bytes: set[bytes] = set()
    for _ in range(tokens_count):
        token: CardanoToken = await ctx.call(CardanoTxItemAck(), CardanoToken)
        _validate_token(token, seen_asset_name_bytes, is_mint=True)
        seen_asset_name_bytes.add(token.asset_name_bytes)
        await confirm_token_minting(ctx, policy_id, token)

        assert token.mint_amount is not None  # _validate_token
        tokens.add(token.asset_name_bytes, token.mint_amount)
예제 #16
0
async def _process_withdrawals(
    ctx: wire.Context,
    keychain: seed.Keychain,
    withdrawals_dict: HashBuilderDict[bytes, int],
    withdrawals_count: int,
    signing_mode: CardanoTxSigningMode,
    protocol_magic: int,
    network_id: int,
    account_path_checker: AccountPathChecker,
) -> None:
    """Read, validate, confirm and serialize the withdrawals."""
    if withdrawals_count == 0:
        return

    # until the CIP with canonical CBOR is finalized storing the seen_withdrawals is the only way we can check for
    # duplicate withdrawals
    seen_withdrawals: set[tuple[int, ...] | bytes] = set()
    for _ in range(withdrawals_count):
        withdrawal: CardanoTxWithdrawal = await ctx.call(
            CardanoTxItemAck(), CardanoTxWithdrawal
        )
        _validate_withdrawal(
            withdrawal, seen_withdrawals, signing_mode, account_path_checker
        )
        await confirm_withdrawal(ctx, withdrawal)
        reward_address_type = (
            CardanoAddressType.REWARD
            if withdrawal.path
            else CardanoAddressType.REWARD_SCRIPT
        )
        reward_address = derive_address_bytes(
            keychain,
            CardanoAddressParametersType(
                address_type=reward_address_type,
                address_n_staking=withdrawal.path,
                script_staking_hash=withdrawal.script_hash,
            ),
            protocol_magic,
            network_id,
        )

        withdrawals_dict.add(reward_address, withdrawal.amount)
예제 #17
0
async def _process_pool_owners(
    ctx: wire.Context,
    keychain: seed.Keychain,
    pool_owners_list: HashBuilderList[bytes],
    owners_count: int,
    protocol_magic: int,
    network_id: int,
    account_path_checker: AccountPathChecker,
) -> None:
    owners_as_path_count = 0
    for _ in range(owners_count):
        owner: CardanoPoolOwner = await ctx.call(CardanoTxItemAck(), CardanoPoolOwner)
        validate_pool_owner(owner, account_path_checker)
        await _show_pool_owner(ctx, keychain, owner, protocol_magic, network_id)

        pool_owners_list.append(cborize_pool_owner(keychain, owner))

        if owner.staking_key_path:
            owners_as_path_count += 1

    assert_certificate_cond(owners_as_path_count == 1)
예제 #18
0
async def _process_asset_groups(
    ctx: wire.Context,
    asset_groups_dict: HashBuilderDict[bytes, HashBuilderDict[bytes, int]],
    asset_groups_count: int,
    should_show_tokens: bool,
) -> None:
    """Read, validate and serialize the asset groups of an output."""
    for _ in range(asset_groups_count):
        asset_group: CardanoAssetGroup = await ctx.call(
            CardanoTxItemAck(), CardanoAssetGroup)
        _validate_asset_group(asset_group)

        tokens: HashBuilderDict[bytes, int] = HashBuilderDict(
            asset_group.tokens_count, INVALID_TOKEN_BUNDLE_OUTPUT)
        with asset_groups_dict.add(asset_group.policy_id, tokens):
            await _process_tokens(
                ctx,
                tokens,
                asset_group.policy_id,
                asset_group.tokens_count,
                should_show_tokens,
            )
예제 #19
0
async def _process_outputs(
    ctx: wire.Context,
    keychain: seed.Keychain,
    outputs_list: HashBuilderList,
    outputs_count: int,
    signing_mode: CardanoTxSigningMode,
    protocol_magic: int,
    network_id: int,
    account_path_checker: AccountPathChecker,
) -> None:
    """Read, validate, confirm and serialize the outputs, return the total non-change output amount."""
    total_amount = 0
    for _ in range(outputs_count):
        output: CardanoTxOutput = await ctx.call(CardanoTxItemAck(),
                                                 CardanoTxOutput)
        _validate_output(
            output,
            signing_mode,
            protocol_magic,
            network_id,
            account_path_checker,
        )

        should_show_output = _should_show_output(output, signing_mode)
        if should_show_output:
            await _show_output(
                ctx,
                keychain,
                output,
                protocol_magic,
                network_id,
                signing_mode,
            )

        output_address = _get_output_address(keychain, protocol_magic,
                                             network_id, output)

        has_datum_hash = output.datum_hash is not None
        output_list: HashBuilderList = HashBuilderList(2 + int(has_datum_hash))
        with outputs_list.append(output_list):
            output_list.append(output_address)
            if output.asset_groups_count == 0:
                # output structure is: [address, amount, datum_hash?]
                output_list.append(output.amount)
            else:
                # output structure is: [address, [amount, asset_groups], datum_hash?]
                output_value_list: HashBuilderList = HashBuilderList(2)
                with output_list.append(output_value_list):
                    output_value_list.append(output.amount)
                    asset_groups_dict: HashBuilderDict[bytes, HashBuilderDict[
                        bytes,
                        int]] = HashBuilderDict(output.asset_groups_count,
                                                INVALID_TOKEN_BUNDLE_OUTPUT)
                    with output_value_list.append(asset_groups_dict):
                        await _process_asset_groups(
                            ctx,
                            asset_groups_dict,
                            output.asset_groups_count,
                            should_show_output,
                        )
            if has_datum_hash:
                output_list.append(output.datum_hash)

        total_amount += output.amount

    if total_amount > LOVELACE_MAX_SUPPLY:
        raise wire.ProcessError("Total transaction amount is out of range!")