Skip to main content
Glama
validators.py9.31 kB
""" Input validation utilities for DeBank API requests. Provides validation functions for common input types including addresses, chain IDs, dates, and token identifiers. """ import re from datetime import datetime from typing import List, Optional def validate_address(address: str) -> str: """ Validate Ethereum address format. Checks that the address: - Starts with '0x' - Contains exactly 40 hexadecimal characters after '0x' - Is a valid hex string Args: address: Ethereum address string to validate Returns: Lowercase address string if valid Raises: ValueError: If address format is invalid Examples: >>> validate_address("0x1234567890123456789012345678901234567890") '0x1234567890123456789012345678901234567890' >>> validate_address("invalid") ValueError: Invalid Ethereum address format """ if not address: raise ValueError("Address cannot be empty") if not isinstance(address, str): raise ValueError("Address must be a string") # Remove whitespace address = address.strip() # Check format: 0x followed by 40 hex characters if not re.match(r'^0x[0-9a-fA-F]{40}$', address): raise ValueError( "Invalid Ethereum address format. " "Address must start with '0x' followed by 40 hexadecimal characters. " f"Got: {address}" ) # Return lowercase for consistency return address.lower() def validate_chain_id( chain_id: str, supported_chains: Optional[List[str]] = None ) -> str: """ Validate chain ID against supported chains. Args: chain_id: Chain identifier to validate supported_chains: Optional list of supported chain IDs. If None, only basic validation is performed. Returns: Validated chain ID string Raises: ValueError: If chain_id is invalid or not supported Examples: >>> validate_chain_id("eth", ["eth", "bsc", "matic"]) 'eth' >>> validate_chain_id("unknown", ["eth", "bsc"]) ValueError: Chain 'unknown' is not supported """ if not chain_id: raise ValueError("Chain ID cannot be empty") if not isinstance(chain_id, str): raise ValueError("Chain ID must be a string") chain_id = chain_id.strip().lower() if not chain_id: raise ValueError("Chain ID cannot be empty or whitespace only") # Check against supported chains if provided if supported_chains is not None: supported_lower = [c.lower() for c in supported_chains] if chain_id not in supported_lower: raise ValueError( f"Chain '{chain_id}' is not supported. " f"Supported chains: {', '.join(supported_chains)}" ) return chain_id def validate_date_format(date_str: str, format_spec: str = "%Y-%m-%d") -> str: """ Validate date string format. Args: date_str: Date string to validate format_spec: Expected date format (default: YYYY-MM-DD) Returns: Validated date string in the specified format Raises: ValueError: If date format is invalid Examples: >>> validate_date_format("2024-01-15") '2024-01-15' >>> validate_date_format("2024-13-45") ValueError: Invalid date format """ if not date_str: raise ValueError("Date string cannot be empty") if not isinstance(date_str, str): raise ValueError("Date must be a string") date_str = date_str.strip() try: # Parse the date to validate format parsed_date = datetime.strptime(date_str, format_spec) # Return in the same format return parsed_date.strftime(format_spec) except ValueError as e: raise ValueError( f"Invalid date format. Expected format: {format_spec}. " f"Got: {date_str}. Error: {str(e)}" ) def validate_token_ids(token_ids: List[str], max_count: int = 100) -> List[str]: """ Validate list of token IDs. Checks that: - Input is a list - List is not empty - List doesn't exceed maximum count - All token IDs are non-empty strings Args: token_ids: List of token identifier strings max_count: Maximum allowed number of token IDs (default: 100) Returns: Validated list of token ID strings Raises: ValueError: If validation fails Examples: >>> validate_token_ids(["eth", "usdc", "usdt"]) ['eth', 'usdc', 'usdt'] >>> validate_token_ids([]) ValueError: Token IDs list cannot be empty """ if not isinstance(token_ids, list): raise ValueError("Token IDs must be provided as a list") if len(token_ids) == 0: raise ValueError("Token IDs list cannot be empty") if len(token_ids) > max_count: raise ValueError( f"Too many token IDs provided. Maximum allowed: {max_count}, " f"got: {len(token_ids)}" ) # Validate each token ID validated_ids = [] for i, token_id in enumerate(token_ids): if not isinstance(token_id, str): raise ValueError(f"Token ID at index {i} must be a string, got: {type(token_id)}") token_id = token_id.strip() if not token_id: raise ValueError(f"Token ID at index {i} cannot be empty or whitespace only") validated_ids.append(token_id) return validated_ids def validate_protocol_id(protocol_id: str) -> str: """ Validate protocol ID format. Args: protocol_id: Protocol identifier to validate Returns: Validated protocol ID string Raises: ValueError: If protocol_id is invalid """ if not protocol_id: raise ValueError("Protocol ID cannot be empty") if not isinstance(protocol_id, str): raise ValueError("Protocol ID must be a string") protocol_id = protocol_id.strip() if not protocol_id: raise ValueError("Protocol ID cannot be empty or whitespace only") return protocol_id def validate_pagination_params( page_num: Optional[int] = None, page_count: Optional[int] = None, max_page_count: int = 100 ) -> tuple[Optional[int], Optional[int]]: """ Validate pagination parameters. Args: page_num: Page number (1-indexed) page_count: Number of items per page max_page_count: Maximum allowed items per page Returns: Tuple of (validated_page_num, validated_page_count) Raises: ValueError: If pagination parameters are invalid """ if page_num is not None: if not isinstance(page_num, int): raise ValueError("page_num must be an integer") if page_num < 1: raise ValueError("page_num must be >= 1") if page_count is not None: if not isinstance(page_count, int): raise ValueError("page_count must be an integer") if page_count < 1: raise ValueError("page_count must be >= 1") if page_count > max_page_count: raise ValueError( f"page_count cannot exceed {max_page_count}, got: {page_count}" ) return page_num, page_count def validate_time_range( start_time: Optional[int] = None, end_time: Optional[int] = None ) -> tuple[Optional[int], Optional[int]]: """ Validate Unix timestamp time range. Args: start_time: Start timestamp (Unix time in seconds) end_time: End timestamp (Unix time in seconds) Returns: Tuple of (validated_start_time, validated_end_time) Raises: ValueError: If time range is invalid """ if start_time is not None: if not isinstance(start_time, int): raise ValueError("start_time must be an integer (Unix timestamp)") if start_time < 0: raise ValueError("start_time must be a positive Unix timestamp") if end_time is not None: if not isinstance(end_time, int): raise ValueError("end_time must be an integer (Unix timestamp)") if end_time < 0: raise ValueError("end_time must be a positive Unix timestamp") if start_time is not None and end_time is not None: if start_time >= end_time: raise ValueError("start_time must be less than end_time") return start_time, end_time def validate_tx_hash(tx_hash: str) -> str: """ Validate transaction hash format. Args: tx_hash: Transaction hash to validate Returns: Validated transaction hash (lowercase) Raises: ValueError: If transaction hash format is invalid """ if not tx_hash: raise ValueError("Transaction hash cannot be empty") if not isinstance(tx_hash, str): raise ValueError("Transaction hash must be a string") tx_hash = tx_hash.strip() # Transaction hash should be 0x followed by 64 hex characters if not re.match(r'^0x[0-9a-fA-F]{64}$', tx_hash): raise ValueError( "Invalid transaction hash format. " "Hash must start with '0x' followed by 64 hexadecimal characters. " f"Got: {tx_hash}" ) return tx_hash.lower()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/caiovicentino/debank-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server