text: from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
  
  from rotkehlchen.accounting.structures.base import (
      HistoryBaseEntry,
      HistoryEventSubType,
      HistoryEventType,
  )
  from rotkehlchen.chain.ethereum.decoding.interfaces import DecoderInterface
  from rotkehlchen.chain.ethereum.decoding.structures import ActionItem
  from rotkehlchen.chain.ethereum.decoding.utils import maybe_reshuffle_events
  from rotkehlchen.chain.ethereum.structures import EthereumTxReceiptLog
  from rotkehlchen.chain.ethereum.types import string_to_ethereum_address
  from rotkehlchen.chain.ethereum.utils import asset_normalized_value, ethaddress_to_asset
  from rotkehlchen.types import ChecksumEthAddress, EthereumTransaction
  from rotkehlchen.utils.misc import hex_or_bytes_to_address, hex_or_bytes_to_int
  
  from ..constants import CPT_ONEINCH_V2
  
  if TYPE_CHECKING:
      from rotkehlchen.chain.ethereum.decoding.base import BaseDecoderTools
      from rotkehlchen.chain.ethereum.manager import EthereumManager
      from rotkehlchen.user_messages import MessagesAggregator
  
  SWAPPED = b'v\xaf"J\x148e\xa5\x0bAIn\x1asb&\x98i,V\\\x12\x14\xbc\x86/\x18\xe2-\x82\x9c^'
  
  
  class Oneinchv2Decoder(DecoderInterface):  # lgtm[py/missing-call-to-init]
      def __init__(  # pylint: disable=super-init-not-called
              self,
              ethereum_manager: 'EthereumManager',  # pylint: disable=unused-argument
              base_tools: 'BaseDecoderTools',
              msg_aggregator: 'MessagesAggregator',  # pylint: disable=unused-argument
      ) -> None:
          self.base = base_tools
  
      def _decode_swapped(  # pylint: disable=no-self-use
              self,
              tx_log: EthereumTxReceiptLog,
              transaction: EthereumTransaction,  # pylint: disable=unused-argument
              decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
              all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
      ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
          sender = hex_or_bytes_to_address(tx_log.topics[1])
          source_token_address = hex_or_bytes_to_address(tx_log.topics[2])
          destination_token_address = hex_or_bytes_to_address(tx_log.topics[3])
  
          source_token = ethaddress_to_asset(source_token_address)
          if source_token is None:
              return None, None
          destination_token = ethaddress_to_asset(destination_token_address)
          if destination_token is None:
              return None, None
  
          receiver = hex_or_bytes_to_address(tx_log.data[0:32])
          spent_amount_raw = hex_or_bytes_to_int(tx_log.data[64:96])
          return_amount_raw = hex_or_bytes_to_int(tx_log.data[96:128])
          spent_amount = asset_normalized_value(amount=spent_amount_raw, asset=source_token)
          return_amount = asset_normalized_value(amount=return_amount_raw, asset=destination_token)
  
          out_event = in_event = None
          for event in decoded_events:
              # Now find the sending and receiving events
              if event.event_type == HistoryEventType.SPEND and event.location_label == sender and spent_amount == event.balance.amount and source_token == event.asset:  # noqa: E501
                  event.event_type = HistoryEventType.TRADE
                  event.event_subtype = HistoryEventSubType.SPEND
                  event.counterparty = CPT_ONEINCH_V2
                  event.notes = f'Swap {spent_amount} {source_token.symbol} in {CPT_ONEINCH_V2}'  # noqa: E501
                  out_event = event
              elif event.event_type == HistoryEventType.RECEIVE and event.location_label == sender and receiver == event.location_label and return_amount == event.balance.amount and destination_token == event.asset:  # noqa: E501
                  event.event_type = HistoryEventType.TRADE
                  event.event_subtype = HistoryEventSubType.RECEIVE
                  event.counterparty = CPT_ONEINCH_V2
                  event.notes = f'Receive {return_amount} {destination_token.symbol} from {CPT_ONEINCH_V2} swap'  # noqa: E501
                  # use this index as the event may be an ETH transfer and appear at the start
                  event.sequence_index = tx_log.log_index
                  in_event = event
  
          maybe_reshuffle_events(out_event=out_event, in_event=in_event, events_list=decoded_events)
          return None, None
  
      def decode_action(
              self,
              tx_log: EthereumTxReceiptLog,
              transaction: EthereumTransaction,
              decoded_events: List[HistoryBaseEntry],  # pylint: disable=unused-argument
              all_logs: List[EthereumTxReceiptLog],  # pylint: disable=unused-argument
              action_items: Optional[List[ActionItem]],  # pylint: disable=unused-argument
      ) -> Tuple[Optional[HistoryBaseEntry], Optional[ActionItem]]:
          if tx_log.topics[0] == SWAPPED:
              return self._decode_swapped(tx_log=tx_log, transaction=transaction, decoded_events=decoded_events, all_logs=all_logs)  # noqa: E501
  
          return None, None
  
      # -- DecoderInterface methods
  
      def addresses_to_decoders(self) -> Dict[ChecksumEthAddress, Tuple[Any, ...]]:
          return {
              string_to_ethereum_address('0x111111125434b319222CdBf8C261674aDB56F3ae'): (self.decode_action,),  # noqa: E501
          }
  
      def counterparties(self) -> List[str]:
          return [CPT_ONEINCH_V2]
  