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