async def _process_collateral_return(self) -> None: output: messages.CardanoTxOutput = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxOutput) self._validate_collateral_return(output) should_show_init = self._should_show_collateral_return_init(output) should_show_tokens = self._should_show_collateral_return_tokens(output) if should_show_init: await self._show_collateral_return_init(output) # Datums and reference scripts are forbidden, see _validate_collateral_return. output_items_count = 2 if output.format == CardanoTxOutputSerializationFormat.ARRAY_LEGACY: output_list: HashBuilderList = HashBuilderList(output_items_count) with self.tx_dict.add(TX_BODY_KEY_COLLATERAL_RETURN, output_list): await self._process_legacy_output(output_list, output, should_show_tokens) elif output.format == CardanoTxOutputSerializationFormat.MAP_BABBAGE: output_dict: HashBuilderDict[int, Any] = HashBuilderDict( output_items_count, wire.ProcessError("Invalid collateral return")) with self.tx_dict.add(TX_BODY_KEY_COLLATERAL_RETURN, output_dict): await self._process_babbage_output(output_dict, output, should_show_tokens) else: raise RuntimeError # should be unreachable
async def _process_inputs( self, inputs_list: HashBuilderList[tuple[bytes, int]]) -> None: for _ in range(self.msg.inputs_count): input: messages.CardanoTxInput = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxInput) self._validate_input(input) await self._show_input(input) inputs_list.append((input.prev_hash, input.prev_index))
async def _process_reference_inputs( self, reference_inputs_list: HashBuilderList[tuple[bytes, int]]) -> None: for _ in range(self.msg.reference_inputs_count): reference_input: messages.CardanoTxReferenceInput = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxReferenceInput) self._validate_reference_input(reference_input) await self._show_if_showing_details( layout.confirm_reference_input(self.ctx, reference_input)) reference_inputs_list.append( (reference_input.prev_hash, reference_input.prev_index))
async def _process_pool_relays( self, relays_list: HashBuilderList[cbor.CborSequence], relays_count: int, ) -> None: for _ in range(relays_count): relay: messages.CardanoPoolRelayParameters = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoPoolRelayParameters) certificates.validate_pool_relay(relay) relays_list.append(certificates.cborize_pool_relay(relay))
async def _process_withdrawals( self, withdrawals_dict: HashBuilderDict[bytes, int]) -> None: for _ in range(self.msg.withdrawals_count): withdrawal: messages.CardanoTxWithdrawal = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxWithdrawal) self._validate_withdrawal(withdrawal) address_bytes = self._derive_withdrawal_address_bytes(withdrawal) await self._show_if_showing_details( layout.confirm_withdrawal(self.ctx, withdrawal, address_bytes, self.msg.network_id)) withdrawals_dict.add(address_bytes, withdrawal.amount)
async def _process_required_signers( self, required_signers_list: HashBuilderList[bytes]) -> None: for _ in range(self.msg.required_signers_count): required_signer: messages.CardanoTxRequiredSigner = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxRequiredSigner) self._validate_required_signer(required_signer) await self._show_if_showing_details( layout.confirm_required_signer(self.ctx, required_signer)) key_hash = required_signer.key_hash or get_public_key_hash( self.keychain, required_signer.key_path) required_signers_list.append(key_hash)
async def _process_outputs(self, outputs_list: HashBuilderList) -> None: total_amount = 0 for _ in range(self.msg.outputs_count): output: messages.CardanoTxOutput = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxOutput) await self._process_output(outputs_list, output) total_amount += output.amount if total_amount > LOVELACE_MAX_SUPPLY: raise wire.ProcessError( "Total transaction amount is out of range!")
async def _process_minting( self, minting_dict: HashBuilderDict[bytes, HashBuilderDict]) -> None: token_minting: messages.CardanoTxMint = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxMint) await layout.warn_tx_contains_mint(self.ctx) for _ in range(token_minting.asset_groups_count): asset_group: messages.CardanoAssetGroup = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoAssetGroup) self._validate_asset_group(asset_group, is_mint=True) tokens: HashBuilderDict[bytes, int] = HashBuilderDict( asset_group.tokens_count, wire.ProcessError("Invalid mint token bundle")) with minting_dict.add(asset_group.policy_id, tokens): await self._process_minting_tokens( tokens, asset_group.policy_id, asset_group.tokens_count, )
async def _process_minting_tokens( self, tokens: HashBuilderDict[bytes, int], policy_id: bytes, tokens_count: int, ) -> None: for _ in range(tokens_count): token: messages.CardanoToken = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoToken) self._validate_token(token, is_mint=True) await layout.confirm_token_minting(self.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_pool_owners(self, pool_owners_list: HashBuilderList[bytes], owners_count: int) -> None: owners_as_path_count = 0 for _ in range(owners_count): owner: messages.CardanoPoolOwner = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoPoolOwner) certificates.validate_pool_owner(owner, self.account_path_checker) await self._show_pool_owner(owner) pool_owners_list.append( certificates.cborize_pool_owner(self.keychain, owner)) if owner.staking_key_path: owners_as_path_count += 1 certificates.assert_cond(owners_as_path_count == 1)
async def _process_witness_requests( self, tx_hash: bytes) -> CardanoTxResponseType: response: CardanoTxResponseType = messages.CardanoTxItemAck() for _ in range(self.msg.witness_requests_count): witness_request = await self.ctx.call( response, messages.CardanoTxWitnessRequest) self._validate_witness_request(witness_request) path = witness_request.path await self._show_witness_request(path) if seed.is_byron_path(path): response = self._get_byron_witness(path, tx_hash) else: response = self._get_shelley_witness(path, tx_hash) return response
async def _process_tokens( self, tokens_dict: HashBuilderDict[bytes, int], policy_id: bytes, tokens_count: int, should_show_tokens: bool, ) -> None: for _ in range(tokens_count): token: messages.CardanoToken = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoToken) self._validate_token(token) if should_show_tokens: await layout.confirm_sending_token(self.ctx, policy_id, token) assert token.amount is not None # _validate_token tokens_dict.add(token.asset_name_bytes, token.amount)
async def _process_asset_groups( self, asset_groups_dict: HashBuilderDict[bytes, HashBuilderDict[bytes, int]], asset_groups_count: int, should_show_tokens: bool, ) -> None: for _ in range(asset_groups_count): asset_group: messages.CardanoAssetGroup = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoAssetGroup) self._validate_asset_group(asset_group) tokens: HashBuilderDict[bytes, int] = HashBuilderDict( asset_group.tokens_count, wire.ProcessError("Invalid token bundle in output"), ) with asset_groups_dict.add(asset_group.policy_id, tokens): await self._process_tokens( tokens, asset_group.policy_id, asset_group.tokens_count, should_show_tokens, )
async def _process_certificates( self, certificates_list: HashBuilderList) -> None: for _ in range(self.msg.certificates_count): certificate: messages.CardanoTxCertificate = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxCertificate) self._validate_certificate(certificate) await self._show_certificate(certificate) 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 certificates.cborize_pool_registration_init( 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 self._process_pool_owners( pool_owners_list, pool_parameters.owners_count) relays_list: HashBuilderList[ cbor.CborSequence] = HashBuilderList( pool_parameters.relays_count) with pool_items_list.append(relays_list): await self._process_pool_relays( relays_list, pool_parameters.relays_count) pool_items_list.append( certificates.cborize_pool_metadata( pool_parameters.metadata)) else: certificates_list.append( certificates.cborize(self.keychain, certificate))
async def _process_auxiliary_data(self) -> None: data: messages.CardanoTxAuxiliaryData = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxAuxiliaryData) auxiliary_data.validate(data) ( auxiliary_data_hash, auxiliary_data_supplement, ) = auxiliary_data.get_hash_and_supplement(self.keychain, data, self.msg.protocol_magic, self.msg.network_id) await auxiliary_data.show( self.ctx, self.keychain, auxiliary_data_hash, data.catalyst_registration_parameters, self.msg.protocol_magic, self.msg.network_id, self.should_show_details, ) self.tx_dict.add(TX_BODY_KEY_AUXILIARY_DATA, auxiliary_data_hash) await self.ctx.call(auxiliary_data_supplement, messages.CardanoTxHostAck)
async def _process_reference_script( self, reference_script_cbor: HashBuilderEmbeddedCBOR, reference_script_size: int, should_show: bool, ) -> None: assert reference_script_size > 0 chunks_count = self._get_chunks_count(reference_script_size) for chunk_number in range(chunks_count): chunk: messages.CardanoTxReferenceScriptChunk = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxReferenceScriptChunk) self._validate_chunk( chunk.data, chunk_number, chunks_count, wire.ProcessError("Invalid reference script chunk"), ) if chunk_number == 0 and should_show: await self._show_if_showing_details( layout.confirm_reference_script(self.ctx, chunk.data, reference_script_size)) reference_script_cbor.add(chunk.data)
async def _process_inline_datum( self, inline_datum_cbor: HashBuilderEmbeddedCBOR, inline_datum_size: int, should_show: bool, ) -> None: assert inline_datum_size > 0 chunks_count = self._get_chunks_count(inline_datum_size) for chunk_number in range(chunks_count): chunk: messages.CardanoTxInlineDatumChunk = await self.ctx.call( messages.CardanoTxItemAck(), messages.CardanoTxInlineDatumChunk) self._validate_chunk( chunk.data, chunk_number, chunks_count, wire.ProcessError("Invalid inline datum chunk"), ) if chunk_number == 0 and should_show: await self._show_if_showing_details( layout.confirm_inline_datum(self.ctx, chunk.data, inline_datum_size)) inline_datum_cbor.add(chunk.data)