mirror of
https://github.com/chainstacklabs/pumpfun-bonkfun-bot.git
synced 2026-08-01 17:57:43 +00:00
wip(core): platform aware trading
This commit is contained in:
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user