Automated Action cae8527a4b s
2025-05-28 22:44:22 +00:00

139 lines
4.5 KiB
Python

"""
Registry of instruction parsers
"""
import base64
import logging
from typing import Dict, List, Optional
from app.parsers.base import InstructionParser
from app.parsers.token_program import TokenProgramParser
from app.parsers.serum_dex import SerumDexParser
from app.parsers.jupiter import JupiterParser
from app.parsers.raydium import RaydiumSwapParser, RaydiumLiquidityParser
logger = logging.getLogger(__name__)
class InstructionParserRegistry:
"""
Registry of instruction parsers for different Solana programs
"""
def __init__(self):
"""
Initialize the registry with available parsers
"""
self.parsers: Dict[str, InstructionParser] = {}
self.register_default_parsers()
def register_parser(self, parser: InstructionParser) -> None:
"""
Register a parser for a specific program
Args:
parser: Parser instance to register
"""
self.parsers[parser.program_id] = parser
logger.debug(f"Registered parser for program: {parser.program_id}")
def register_default_parsers(self) -> None:
"""
Register the default set of parsers
"""
# Register SPL Token Program parser
self.register_parser(TokenProgramParser())
# Register DEX parsers
self.register_parser(SerumDexParser())
self.register_parser(JupiterParser())
self.register_parser(RaydiumSwapParser())
self.register_parser(RaydiumLiquidityParser())
def get_parser_for_program(self, program_id: str) -> Optional[InstructionParser]:
"""
Get a parser for a specific program ID
Args:
program_id: The program ID to get a parser for
Returns:
Parser instance if one exists for the program, None otherwise
"""
# First try exact match
if program_id in self.parsers:
return self.parsers[program_id]
# Then try parsers that can handle multiple program IDs
for parser in self.parsers.values():
if parser.can_handle(program_id):
return parser
return None
def parse_transaction_instructions(self, transaction_data: Dict) -> List[Dict]:
"""
Parse all instructions in a transaction
Args:
transaction_data: Transaction data from RPC response
Returns:
List of parsed instructions
"""
parsed_instructions = []
if not transaction_data or "transaction" not in transaction_data:
return parsed_instructions
tx = transaction_data["transaction"]
if "message" not in tx:
return parsed_instructions
message = tx["message"]
# Extract account addresses
accounts = message.get("accountKeys", [])
# Parse each instruction
instructions = message.get("instructions", [])
for instruction in instructions:
program_id = instruction.get("programId")
if not program_id:
continue
# Get parser for this program
parser = self.get_parser_for_program(program_id)
# Parse instruction data
instruction_data_b64 = instruction.get("data", "")
try:
instruction_data = base64.b64decode(instruction_data_b64)
except Exception:
# If not base64, try other formats or skip
instruction_data = b""
# Parse the instruction
if parser:
try:
parsed = parser.parse_instruction(instruction, accounts, instruction_data)
parsed_instructions.append(parsed)
except Exception as e:
logger.error(f"Error parsing instruction: {str(e)}")
parsed_instructions.append({
"type": "error",
"program_id": program_id,
"error": str(e),
})
else:
# No parser available for this program
parsed_instructions.append({
"type": "unknown",
"program_id": program_id,
"data": instruction_data_b64,
})
return parsed_instructions
# Singleton instance
parser_registry = InstructionParserRegistry()