wip(core): platform aware trading

This commit is contained in:
smypmsa
2025-08-02 09:25:39 +00:00
parent 60c452da0f
commit bb35101a8f
31 changed files with 3907 additions and 1094 deletions
+280
View File
@@ -0,0 +1,280 @@
"""
Platform factory and registry for managing multiple trading platforms.
This module provides a centralized way to instantiate and access
platform-specific implementations of the trading interfaces.
"""
from dataclasses import dataclass
from typing import Any, Dict, Optional, Type
from core.client import SolanaClient
from interfaces.core import (
AddressProvider,
CurveManager,
EventParser,
InstructionBuilder,
Platform,
)
@dataclass
class PlatformImplementations:
"""Container for all platform-specific implementations."""
address_provider: AddressProvider
instruction_builder: InstructionBuilder
curve_manager: CurveManager
event_parser: EventParser
class PlatformRegistry:
"""Registry for platform implementations."""
def __init__(self):
self._implementations: dict[Platform, dict[str, type]] = {}
self._instances: dict[Platform, PlatformImplementations] = {}
def register_platform(
self,
platform: Platform,
address_provider_class: type[AddressProvider],
instruction_builder_class: type[InstructionBuilder],
curve_manager_class: type[CurveManager],
event_parser_class: type[EventParser]
) -> None:
"""Register platform implementations.
Args:
platform: Platform enum value
address_provider_class: AddressProvider implementation class
instruction_builder_class: InstructionBuilder implementation class
curve_manager_class: CurveManager implementation class
event_parser_class: EventParser implementation class
"""
self._implementations[platform] = {
'address_provider': address_provider_class,
'instruction_builder': instruction_builder_class,
'curve_manager': curve_manager_class,
'event_parser': event_parser_class
}
def create_platform_implementations(
self,
platform: Platform,
client: SolanaClient,
**kwargs: Any
) -> PlatformImplementations:
"""Create platform implementation instances.
Args:
platform: Platform to create implementations for
client: Solana RPC client
**kwargs: Additional arguments for implementation constructors
Returns:
PlatformImplementations containing all interface implementations
Raises:
ValueError: If platform is not registered
"""
if platform not in self._implementations:
raise ValueError(f"Platform {platform} is not registered")
# Check if we already have instances for this platform
if platform in self._instances:
return self._instances[platform]
impl_classes = self._implementations[platform]
# Create instances
address_provider = impl_classes['address_provider']()
instruction_builder = impl_classes['instruction_builder']()
curve_manager = impl_classes['curve_manager'](client)
event_parser = impl_classes['event_parser']()
implementations = PlatformImplementations(
address_provider=address_provider,
instruction_builder=instruction_builder,
curve_manager=curve_manager,
event_parser=event_parser
)
# Cache the instances
self._instances[platform] = implementations
return implementations
def get_platform_implementations(self, platform: Platform) -> PlatformImplementations | None:
"""Get cached platform implementations.
Args:
platform: Platform to get implementations for
Returns:
PlatformImplementations if available, None otherwise
"""
return self._instances.get(platform)
def get_supported_platforms(self) -> list[Platform]:
"""Get list of supported platforms.
Returns:
List of registered platforms
"""
return list(self._implementations.keys())
def is_platform_supported(self, platform: Platform) -> bool:
"""Check if a platform is supported.
Args:
platform: Platform to check
Returns:
True if platform is registered, False otherwise
"""
return platform in self._implementations
class PlatformFactory:
"""Factory for creating platform-specific implementations."""
def __init__(self):
self.registry = PlatformRegistry()
self._setup_default_platforms()
def _setup_default_platforms(self) -> None:
"""Setup default platform registrations.
This will be populated as we implement each platform.
"""
# Platforms will be registered here as they are implemented
# Example:
# from platforms.pumpfun import PumpFunAddressProvider, PumpFunInstructionBuilder, ...
# self.registry.register_platform(
# Platform.PUMP_FUN,
# PumpFunAddressProvider,
# PumpFunInstructionBuilder,
# PumpFunCurveManager,
# PumpFunEventParser
# )
pass
def create_for_platform(
self,
platform: Platform,
client: SolanaClient,
**config: Any
) -> PlatformImplementations:
"""Create all implementations for a specific platform.
Args:
platform: Platform to create implementations for
client: Solana RPC client
**config: Platform-specific configuration
Returns:
PlatformImplementations containing all interface implementations
"""
return self.registry.create_platform_implementations(platform, client, **config)
def get_address_provider(self, platform: Platform, client: SolanaClient) -> AddressProvider:
"""Get address provider for platform.
Args:
platform: Platform to get provider for
client: Solana RPC client
Returns:
AddressProvider implementation
"""
implementations = self.registry.create_platform_implementations(platform, client)
return implementations.address_provider
def get_instruction_builder(self, platform: Platform, client: SolanaClient) -> InstructionBuilder:
"""Get instruction builder for platform.
Args:
platform: Platform to get builder for
client: Solana RPC client
Returns:
InstructionBuilder implementation
"""
implementations = self.registry.create_platform_implementations(platform, client)
return implementations.instruction_builder
def get_curve_manager(self, platform: Platform, client: SolanaClient) -> CurveManager:
"""Get curve manager for platform.
Args:
platform: Platform to get manager for
client: Solana RPC client
Returns:
CurveManager implementation
"""
implementations = self.registry.create_platform_implementations(platform, client)
return implementations.curve_manager
def get_event_parser(self, platform: Platform, client: SolanaClient) -> EventParser:
"""Get event parser for platform.
Args:
platform: Platform to get parser for
client: Solana RPC client
Returns:
EventParser implementation
"""
implementations = self.registry.create_platform_implementations(platform, client)
return implementations.event_parser
def get_supported_platforms(self) -> list[Platform]:
"""Get list of supported platforms.
Returns:
List of supported platforms
"""
return self.registry.get_supported_platforms()
# Global factory instance
platform_factory = PlatformFactory()
def get_platform_implementations(platform: Platform, client: SolanaClient) -> PlatformImplementations:
"""Convenience function to get platform implementations.
Args:
platform: Platform to get implementations for
client: Solana RPC client
Returns:
PlatformImplementations containing all interface implementations
"""
return platform_factory.create_for_platform(platform, client)
def register_platform_implementations(
platform: Platform,
address_provider_class: type[AddressProvider],
instruction_builder_class: type[InstructionBuilder],
curve_manager_class: type[CurveManager],
event_parser_class: type[EventParser]
) -> None:
"""Register platform implementations with the global factory.
Args:
platform: Platform enum value
address_provider_class: AddressProvider implementation class
instruction_builder_class: InstructionBuilder implementation class
curve_manager_class: CurveManager implementation class
event_parser_class: EventParser implementation class
"""
platform_factory.registry.register_platform(
platform,
address_provider_class,
instruction_builder_class,
curve_manager_class,
event_parser_class
)
+363
View File
@@ -0,0 +1,363 @@
"""
Core interfaces for multi-platform trading bot architecture.
This module defines the abstract base classes that each trading platform
must implement to enable unified trading operations across different protocols.
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum
from typing import Any
from solders.instruction import Instruction
from solders.pubkey import Pubkey
class Platform(Enum):
"""Supported trading platforms."""
PUMP_FUN = "pump_fun"
LETS_BONK = "lets_bonk"
@dataclass
class TokenInfo:
"""Enhanced token information with platform support."""
# Core token data
name: str
symbol: str
uri: str
mint: Pubkey
# Platform-specific fields
platform: Platform
bonding_curve: Pubkey | None = None # pump.fun specific
associated_bonding_curve: Pubkey | None = None # pump.fun specific
pool_state: Pubkey | None = None # LetsBonk specific
base_vault: Pubkey | None = None # LetsBonk specific
quote_vault: Pubkey | None = None # LetsBonk specific
# Common fields
user: Pubkey | None = None
creator: Pubkey | None = None
creator_vault: Pubkey | None = None
# Metadata
creation_timestamp: float | None = None
additional_data: dict[str, Any] | None = None
class AddressProvider(ABC):
"""Abstract interface for platform-specific address management."""
@property
@abstractmethod
def platform(self) -> Platform:
"""Get the platform this provider serves."""
pass
@property
@abstractmethod
def program_id(self) -> Pubkey:
"""Get the main program ID for this platform."""
pass
@abstractmethod
def get_system_addresses(self) -> dict[str, Pubkey]:
"""Get all system addresses required for this platform.
Returns:
Dictionary mapping address names to Pubkey objects
"""
pass
@abstractmethod
def derive_pool_address(self, base_mint: Pubkey, quote_mint: Pubkey | None = None) -> Pubkey:
"""Derive the pool/curve address for trading pair.
Args:
base_mint: Base token mint address
quote_mint: Quote token mint address (if applicable)
Returns:
Pool/curve address for the trading pair
"""
pass
@abstractmethod
def derive_user_token_account(self, user: Pubkey, mint: Pubkey) -> Pubkey:
"""Derive user's token account address.
Args:
user: User's wallet address
mint: Token mint address
Returns:
User's token account address
"""
pass
@abstractmethod
def get_additional_accounts(self, token_info: TokenInfo) -> dict[str, Pubkey]:
"""Get platform-specific additional accounts needed for trading.
Args:
token_info: Token information
Returns:
Dictionary of additional account addresses
"""
pass
class InstructionBuilder(ABC):
"""Abstract interface for building platform-specific trading instructions."""
@property
@abstractmethod
def platform(self) -> Platform:
"""Get the platform this builder serves."""
pass
@abstractmethod
async def build_buy_instruction(
self,
token_info: TokenInfo,
user: Pubkey,
amount_in: int,
minimum_amount_out: int,
address_provider: AddressProvider
) -> list[Instruction]:
"""Build buy instruction(s) for the platform.
Args:
token_info: Token information
user: User's wallet address
amount_in: Amount of quote tokens to spend
minimum_amount_out: Minimum base tokens expected
address_provider: Platform address provider
Returns:
List of instructions needed for the buy operation
"""
pass
@abstractmethod
async def build_sell_instruction(
self,
token_info: TokenInfo,
user: Pubkey,
amount_in: int,
minimum_amount_out: int,
address_provider: AddressProvider
) -> list[Instruction]:
"""Build sell instruction(s) for the platform.
Args:
token_info: Token information
user: User's wallet address
amount_in: Amount of base tokens to sell
minimum_amount_out: Minimum quote tokens expected
address_provider: Platform address provider
Returns:
List of instructions needed for the sell operation
"""
pass
@abstractmethod
def get_required_accounts_for_buy(
self,
token_info: TokenInfo,
user: Pubkey,
address_provider: AddressProvider
) -> list[Pubkey]:
"""Get list of accounts required for buy operation (for priority fee calculation).
Args:
token_info: Token information
user: User's wallet address
address_provider: Platform address provider
Returns:
List of account addresses that will be accessed
"""
pass
@abstractmethod
def get_required_accounts_for_sell(
self,
token_info: TokenInfo,
user: Pubkey,
address_provider: AddressProvider
) -> list[Pubkey]:
"""Get list of accounts required for sell operation (for priority fee calculation).
Args:
token_info: Token information
user: User's wallet address
address_provider: Platform address provider
Returns:
List of account addresses that will be accessed
"""
pass
class CurveManager(ABC):
"""Abstract interface for platform-specific price calculations and pool state management."""
@property
@abstractmethod
def platform(self) -> Platform:
"""Get the platform this manager serves."""
pass
@abstractmethod
async def get_pool_state(self, pool_address: Pubkey) -> dict[str, Any]:
"""Get the current state of a trading pool/curve.
Args:
pool_address: Address of the pool/curve
Returns:
Dictionary containing pool state data
"""
pass
@abstractmethod
async def calculate_price(self, pool_address: Pubkey) -> float:
"""Calculate current token price from pool state.
Args:
pool_address: Address of the pool/curve
Returns:
Current token price in quote token units
"""
pass
@abstractmethod
async def calculate_buy_amount_out(
self,
pool_address: Pubkey,
amount_in: int
) -> int:
"""Calculate expected tokens received for a buy operation.
Args:
pool_address: Address of the pool/curve
amount_in: Amount of quote tokens to spend
Returns:
Expected amount of base tokens to receive
"""
pass
@abstractmethod
async def calculate_sell_amount_out(
self,
pool_address: Pubkey,
amount_in: int
) -> int:
"""Calculate expected quote tokens received for a sell operation.
Args:
pool_address: Address of the pool/curve
amount_in: Amount of base tokens to sell
Returns:
Expected amount of quote tokens to receive
"""
pass
@abstractmethod
async def get_reserves(self, pool_address: Pubkey) -> tuple[int, int]:
"""Get current pool reserves.
Args:
pool_address: Address of the pool/curve
Returns:
Tuple of (base_reserves, quote_reserves)
"""
pass
class EventParser(ABC):
"""Abstract interface for parsing platform-specific token creation events."""
@property
@abstractmethod
def platform(self) -> Platform:
"""Get the platform this parser serves."""
pass
@abstractmethod
def parse_token_creation_from_logs(
self,
logs: list[str],
signature: str
) -> TokenInfo | None:
"""Parse token creation from transaction logs.
Args:
logs: List of log strings from transaction
signature: Transaction signature
Returns:
TokenInfo if token creation found, None otherwise
"""
pass
@abstractmethod
def parse_token_creation_from_instruction(
self,
instruction_data: bytes,
accounts: list[int],
account_keys: list[bytes]
) -> TokenInfo | None:
"""Parse token creation from instruction data.
Args:
instruction_data: Raw instruction data
accounts: List of account indices
account_keys: List of account public keys
Returns:
TokenInfo if token creation found, None otherwise
"""
pass
@abstractmethod
def parse_token_creation_from_geyser(
self,
transaction_info: Any
) -> TokenInfo | None:
"""Parse token creation from Geyser transaction data.
Args:
transaction_info: Geyser transaction information
Returns:
TokenInfo if token creation found, None otherwise
"""
pass
@abstractmethod
def get_program_id(self) -> Pubkey:
"""Get the program ID this parser monitors.
Returns:
Program ID for event filtering
"""
pass
@abstractmethod
def get_instruction_discriminators(self) -> list[bytes]:
"""Get instruction discriminators for token creation.
Returns:
List of discriminator bytes to match
"""
pass