text: from dataclasses import Field, dataclass, fields
  from typing import Collection, Dict, Iterable, Tuple, Union, cast
  
  from eth_utils import decode_hex, encode_hex, to_dict
  
  from eth2.beacon.typing import Epoch, Gwei, Second, Slot, Version
  
  ConfigTypes = Union[Gwei, Slot, Epoch, Second, bytes, int]
  EncodedConfigTypes = Union[str, int]
  
  
  @to_dict
  def _decoder(
      # NOTE: mypy incorrectly thinks `Field` is a generic type
      data: Dict[str, EncodedConfigTypes],
      fields: Collection[Field],  # type: ignore
  ) -> Iterable[Tuple[str, ConfigTypes]]:
      # NOTE: this code is unwieldly but it satisfies `mypy`
      for field in fields:
          if field.type is Gwei:
              yield field.name, Gwei(cast(int, data[field.name]))
          elif field.type is Slot:
              yield field.name, Slot(cast(int, data[field.name]))
          elif field.type is Epoch:
              yield field.name, Epoch(cast(int, data[field.name]))
          elif field.type is Second:
              yield field.name, Second(cast(int, data[field.name]))
          elif field.type is bytes:
              yield field.name, decode_hex(cast(str, data[field.name]))
          elif field.type is Version:
              yield field.name, Version(decode_hex(cast(str, data[field.name])))
          else:
              yield field.name, int(data[field.name])
  
  
  @dataclass(eq=True, frozen=True)
  class Eth2Config:
      # Misc
      MAX_COMMITTEES_PER_SLOT: int
      TARGET_COMMITTEE_SIZE: int
      MAX_VALIDATORS_PER_COMMITTEE: int
      MIN_PER_EPOCH_CHURN_LIMIT: int
      CHURN_LIMIT_QUOTIENT: int
      SHUFFLE_ROUND_COUNT: int
      HYSTERESIS_QUOTIENT: int
      HYSTERESIS_DOWNWARD_MULTIPLIER: int
      HYSTERESIS_UPWARD_MULTIPLIER: int
      # Genesis
      MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: int
      MIN_GENESIS_TIME: int
      # Gwei values,
      MIN_DEPOSIT_AMOUNT: Gwei
      MAX_EFFECTIVE_BALANCE: Gwei
      EJECTION_BALANCE: Gwei
      EFFECTIVE_BALANCE_INCREMENT: Gwei
      # Initial values
      GENESIS_FORK_VERSION: Version
      BLS_WITHDRAWAL_PREFIX: bytes
      # Time parameters
      GENESIS_DELAY: int
      SECONDS_PER_SLOT: Second
      MIN_ATTESTATION_INCLUSION_DELAY: int
      SLOTS_PER_EPOCH: int
      MIN_SEED_LOOKAHEAD: int
      MAX_SEED_LOOKAHEAD: int
      MIN_EPOCHS_TO_INACTIVITY_PENALTY: int
      EPOCHS_PER_ETH1_VOTING_PERIOD: int
      SLOTS_PER_HISTORICAL_ROOT: int
      MIN_VALIDATOR_WITHDRAWABILITY_DELAY: int
      SHARD_COMMITTEE_PERIOD: int
      # State list lengths
      EPOCHS_PER_HISTORICAL_VECTOR: int
      EPOCHS_PER_SLASHINGS_VECTOR: int
      HISTORICAL_ROOTS_LIMIT: int
      VALIDATOR_REGISTRY_LIMIT: int
      # Rewards and penalties
      BASE_REWARD_FACTOR: int
      WHISTLEBLOWER_REWARD_QUOTIENT: int
      PROPOSER_REWARD_QUOTIENT: int
      INACTIVITY_PENALTY_QUOTIENT: int
      MIN_SLASHING_PENALTY_QUOTIENT: int
      # Max operations per block
      MAX_PROPOSER_SLASHINGS: int
      MAX_ATTESTER_SLASHINGS: int
      MAX_ATTESTATIONS: int
      MAX_DEPOSITS: int
      MAX_VOLUNTARY_EXITS: int
      # Fork choice
      SAFE_SLOTS_TO_UPDATE_JUSTIFIED: int
      # Deposit contract
      DEPOSIT_CONTRACT_ADDRESS: bytes
  
      @to_dict
      def to_formatted_dict(self) -> Iterable[Tuple[str, EncodedConfigTypes]]:
          for field in fields(self):
              if field.type in (bytes, Version):
                  encoded_value = encode_hex(getattr(self, field.name))
              else:
                  encoded_value = getattr(self, field.name)
              yield field.name, encoded_value
  
      @classmethod
      def from_formatted_dict(cls, data: Dict[str, EncodedConfigTypes]) -> "Eth2Config":
          # NOTE: mypy does not recognize the kwarg unpacking here...
          return cls(**_decoder(data, fields(cls)))  # type: ignore
  