mirror of
https://github.com/chainstacklabs/pumpfun-bonkfun-bot.git
synced 2026-07-27 15:27:44 +00:00
docs: add rules for cursor, kiro, windsurf
This commit is contained in:
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project Architecture Rules
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
### Package Organization
|
||||||
|
Maintain clear separation of concerns:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── __init__.py
|
||||||
|
├── bot_runner.py # Main entry point
|
||||||
|
├── config_loader.py # Configuration management
|
||||||
|
├── core/ # Core blockchain functionality
|
||||||
|
│ ├── client.py # Solana RPC client abstraction
|
||||||
|
│ ├── wallet.py # Wallet operations
|
||||||
|
│ └── priority_fee/ # Fee management
|
||||||
|
├── platforms/ # Platform-specific implementations
|
||||||
|
│ ├── pumpfun/ # pump.fun specific code
|
||||||
|
│ └── letsbonk/ # letsbonk.fun specific code
|
||||||
|
├── trading/ # Trading logic
|
||||||
|
│ ├── base.py # Base trading classes
|
||||||
|
│ ├── universal_trader.py # Platform-agnostic trader
|
||||||
|
│ └── position.py # Position management
|
||||||
|
├── monitoring/ # Event listening and monitoring
|
||||||
|
│ ├── base_listener.py # Base listener interface
|
||||||
|
│ └── universal_*_listener.py # Specific listeners
|
||||||
|
├── interfaces/ # Abstract base classes
|
||||||
|
└── utils/ # Utilities and helpers
|
||||||
|
├── logger.py # Logging utilities
|
||||||
|
└── idl_manager.py # IDL management
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Naming Conventions
|
||||||
|
- Use snake_case for all Python files and directories
|
||||||
|
- Prefix abstract base classes with "Base" or put in `interfaces/`
|
||||||
|
- Use "Universal" prefix for platform-agnostic implementations
|
||||||
|
- Group related functionality in subdirectories
|
||||||
|
|
||||||
|
## Design Patterns
|
||||||
|
|
||||||
|
### Platform Abstraction
|
||||||
|
Implement platform-specific functionality using the factory pattern:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# interfaces/core.py - Define abstract interfaces
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
class AddressProvider(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def get_program_address(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# platforms/pumpfun/address_provider.py - Concrete implementation
|
||||||
|
class PumpFunAddressProvider(AddressProvider):
|
||||||
|
def get_program_address(self) -> str:
|
||||||
|
return "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Universal Components
|
||||||
|
Create platform-agnostic wrappers that delegate to platform-specific implementations:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class UniversalTrader:
|
||||||
|
def __init__(self, platform: Platform, **kwargs):
|
||||||
|
self.platform = platform
|
||||||
|
self.platform_trader = self._create_platform_trader()
|
||||||
|
|
||||||
|
def _create_platform_trader(self):
|
||||||
|
# Factory method to create platform-specific trader
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
- Use YAML files for bot configurations in `bots/` directory
|
||||||
|
- Support environment variable interpolation with `${VARIABLE}` syntax
|
||||||
|
- Validate configurations before starting bots
|
||||||
|
- Separate environment-specific settings in `.env` files
|
||||||
|
|
||||||
|
## Module Dependencies
|
||||||
|
|
||||||
|
### Import Rules
|
||||||
|
- Core modules should not import from trading or monitoring
|
||||||
|
- Platform-specific modules should only import from their own package and core/interfaces
|
||||||
|
- Avoid circular imports between packages
|
||||||
|
- Use dependency injection for cross-package dependencies
|
||||||
|
|
||||||
|
### Dependency Layers (from low to high level)
|
||||||
|
1. **utils/** - Utilities and helpers (no business logic dependencies)
|
||||||
|
2. **interfaces/** - Abstract base classes and protocols
|
||||||
|
3. **core/** - Blockchain and infrastructure (depends on utils, interfaces)
|
||||||
|
4. **platforms/** - Platform implementations (depends on core, interfaces)
|
||||||
|
5. **trading/** - Trading logic (depends on core, platforms, interfaces)
|
||||||
|
6. **monitoring/** - Event listening (depends on core, platforms, interfaces)
|
||||||
|
7. **bot_runner.py** - Main orchestrator (depends on all layers)
|
||||||
|
|
||||||
|
## Async Architecture
|
||||||
|
|
||||||
|
### Event Loop Management
|
||||||
|
- Use uvloop for better performance
|
||||||
|
- Set event loop policy at application startup
|
||||||
|
- Use asyncio.create_task() for concurrent operations
|
||||||
|
- Implement proper cleanup on shutdown
|
||||||
|
|
||||||
|
### Connection Management
|
||||||
|
- Use connection pooling for HTTP clients
|
||||||
|
- Implement reconnection logic for WebSocket connections
|
||||||
|
- Cache expensive resources (blockhash, account info)
|
||||||
|
- Use async context managers for resource cleanup
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
### Test Organization
|
||||||
|
- Use `learning-examples/` for integration testing and validation
|
||||||
|
- Test platform-specific components independently
|
||||||
|
- Mock external dependencies (RPC calls, WebSocket connections)
|
||||||
|
- Validate configurations with actual bot startup
|
||||||
|
|
||||||
|
### Test Data
|
||||||
|
- Use test networks for development
|
||||||
|
- Never test with real funds or production keys
|
||||||
|
- Create fixtures for common test scenarios
|
||||||
|
- Document test account requirements
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
- Cache recent blockhash in background task
|
||||||
|
- Cache account information where appropriate
|
||||||
|
- Use local caching for IDL data
|
||||||
|
- Implement TTL for cached data
|
||||||
|
|
||||||
|
### Resource Management
|
||||||
|
- Limit concurrent operations based on RPC provider limits
|
||||||
|
- Implement backoff strategies for failed requests
|
||||||
|
- Use separate processes for production bot instances
|
||||||
|
- Monitor memory usage in long-running processes
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python Code Style Rules
|
||||||
|
|
||||||
|
## Formatting Standards
|
||||||
|
|
||||||
|
### Ruff Configuration Compliance
|
||||||
|
- Use 88 character line length limit
|
||||||
|
- Use 4 spaces for indentation (never tabs)
|
||||||
|
- Use double quotes for strings consistently
|
||||||
|
- Target Python 3.11+ features and syntax
|
||||||
|
- Enable automatic import sorting and organization
|
||||||
|
|
||||||
|
### Import Organization
|
||||||
|
```python
|
||||||
|
# Standard library imports first
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Third-party imports second
|
||||||
|
import aiohttp
|
||||||
|
from solana.rpc.async_api import AsyncClient
|
||||||
|
|
||||||
|
# Local imports last
|
||||||
|
from config_loader import load_bot_config
|
||||||
|
from utils.logger import get_logger
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type Annotations
|
||||||
|
- Add type hints to ALL public functions and methods
|
||||||
|
- Use modern typing syntax (Python 3.9+ union syntax where applicable)
|
||||||
|
- Include return type annotations
|
||||||
|
- Use `from typing import Any` for complex types
|
||||||
|
|
||||||
|
```python
|
||||||
|
def process_transaction(tx_data: dict[str, Any]) -> bool:
|
||||||
|
"""Process transaction data and return success status."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def fetch_data(endpoint: str) -> dict[str, Any] | None:
|
||||||
|
"""Fetch data from endpoint, return None on failure."""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation Standards
|
||||||
|
|
||||||
|
### Docstring Format
|
||||||
|
Use Google-style docstrings for all functions and classes:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def calculate_slippage(amount: float, slippage_percent: float) -> float:
|
||||||
|
"""Calculate slippage amount for a trade.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
amount: The trade amount in SOL
|
||||||
|
slippage_percent: Slippage percentage (0.1 = 10%)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The calculated slippage amount
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If slippage_percent is negative
|
||||||
|
"""
|
||||||
|
if slippage_percent < 0:
|
||||||
|
raise ValueError("Slippage percentage cannot be negative")
|
||||||
|
return amount * slippage_percent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Comprehensive Exception Handling
|
||||||
|
- Use try-catch blocks for all external operations (RPC calls, file I/O)
|
||||||
|
- Log exceptions with context using `logging.exception()`
|
||||||
|
- Provide meaningful error messages
|
||||||
|
- Don't suppress exceptions without good reason
|
||||||
|
|
||||||
|
```python
|
||||||
|
try:
|
||||||
|
result = await client.get_account_info(address)
|
||||||
|
logger.info(f"Successfully fetched account info for {address}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to fetch account info for {address}: {e}")
|
||||||
|
raise
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging Standards
|
||||||
|
|
||||||
|
### Logger Usage
|
||||||
|
- Use `get_logger(__name__)` pattern consistently
|
||||||
|
- Import from `utils.logger`
|
||||||
|
- Use appropriate log levels (DEBUG, INFO, WARNING, ERROR)
|
||||||
|
- Include context in log messages
|
||||||
|
|
||||||
|
```python
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
# Good logging examples
|
||||||
|
logger.info(f"Starting bot '{bot_name}' with platform {platform.value}")
|
||||||
|
logger.warning(f"Transaction failed, attempt {attempt}/{max_attempts}")
|
||||||
|
logger.error(f"Platform {platform.value} is not supported")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Rules
|
||||||
|
|
||||||
|
### Sensitive Data
|
||||||
|
- NEVER hardcode private keys, API tokens, or secrets
|
||||||
|
- Use environment variables for all sensitive configuration
|
||||||
|
- Don't log sensitive information
|
||||||
|
- Validate all external inputs
|
||||||
|
|
||||||
|
### Safe Practices
|
||||||
|
```python
|
||||||
|
# Good - using environment variables
|
||||||
|
private_key = os.getenv("SOLANA_PRIVATE_KEY")
|
||||||
|
if not private_key:
|
||||||
|
raise ValueError("SOLANA_PRIVATE_KEY environment variable is required")
|
||||||
|
|
||||||
|
# Bad - hardcoded secrets
|
||||||
|
private_key = "your_secret_key_here" # NEVER DO THIS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Quality
|
||||||
|
|
||||||
|
### Linting Compliance
|
||||||
|
Ensure code passes all enabled Ruff rules:
|
||||||
|
- Security best practices (S)
|
||||||
|
- Type annotations (ANN)
|
||||||
|
- Exception handling (BLE, TRY)
|
||||||
|
- Code complexity (C90)
|
||||||
|
- Pylint conventions (PL)
|
||||||
|
- No commented-out code (ERA)
|
||||||
|
|
||||||
|
### Performance Considerations
|
||||||
|
- Use async/await for I/O operations
|
||||||
|
- Implement proper connection pooling for HTTP clients
|
||||||
|
- Cache expensive computations when appropriate
|
||||||
|
- Use uvloop for better async performance
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Set uvloop policy at module level
|
||||||
|
import asyncio
|
||||||
|
import uvloop
|
||||||
|
|
||||||
|
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||||
|
```
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
---
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Trading Bot Specific Rules
|
||||||
|
|
||||||
|
## Bot Configuration Standards
|
||||||
|
|
||||||
|
### YAML Configuration Structure
|
||||||
|
Maintain consistent structure across all bot configuration files:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Bot identification
|
||||||
|
name: "bot-sniper-1"
|
||||||
|
platform: "pump_fun" # or "lets_bonk"
|
||||||
|
enabled: true # Allow disabling without removing config
|
||||||
|
separate_process: true # Run in separate process for isolation
|
||||||
|
|
||||||
|
# Environment and connection
|
||||||
|
env_file: ".env"
|
||||||
|
rpc_endpoint: "${SOLANA_NODE_RPC_ENDPOINT}"
|
||||||
|
wss_endpoint: "${SOLANA_NODE_WSS_ENDPOINT}"
|
||||||
|
private_key: "${SOLANA_PRIVATE_KEY}"
|
||||||
|
|
||||||
|
# Platform-specific configurations
|
||||||
|
geyser: # For faster data streams
|
||||||
|
endpoint: "${GEYSER_ENDPOINT}"
|
||||||
|
api_token: "${GEYSER_API_TOKEN}"
|
||||||
|
auth_type: "x-token"
|
||||||
|
|
||||||
|
# Trading parameters
|
||||||
|
trade:
|
||||||
|
buy_amount: 0.0001 # SOL amount
|
||||||
|
buy_slippage: 0.3 # 30%
|
||||||
|
sell_slippage: 0.3
|
||||||
|
exit_strategy: "time_based" # "tp_sl", "manual"
|
||||||
|
extreme_fast_mode: true # Skip validations for speed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variable Usage
|
||||||
|
- Use `${VARIABLE_NAME}` syntax for environment interpolation
|
||||||
|
- Never hardcode sensitive values in YAML files
|
||||||
|
- Validate all required environment variables on startup
|
||||||
|
- Provide clear error messages for missing variables
|
||||||
|
|
||||||
|
## Trading Logic Rules
|
||||||
|
|
||||||
|
### Transaction Handling
|
||||||
|
- Always use priority fees for competitive transaction inclusion
|
||||||
|
- Implement retry mechanisms with exponential backoff
|
||||||
|
- Cache recent blockhash to avoid repeated RPC calls
|
||||||
|
- Use compute unit limits to prevent transaction failures
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Good transaction building pattern
|
||||||
|
instructions = [
|
||||||
|
set_compute_unit_limit(300_000),
|
||||||
|
set_compute_unit_price(priority_fee),
|
||||||
|
# ... trading instructions
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Risk Management
|
||||||
|
- Implement position size limits
|
||||||
|
- Use slippage protection on all trades
|
||||||
|
- Set maximum hold times to prevent stuck positions
|
||||||
|
- Validate token data before trading
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Risk validation example
|
||||||
|
if token_age > self.max_token_age:
|
||||||
|
logger.warning(f"Token {mint} too old ({token_age}s), skipping")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if buy_amount > self.max_position_size:
|
||||||
|
logger.error(f"Buy amount {buy_amount} exceeds max position size")
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exit Strategies
|
||||||
|
Implement multiple exit strategy types:
|
||||||
|
|
||||||
|
1. **Time-based**: Hold for fixed duration
|
||||||
|
2. **Take Profit/Stop Loss**: Price-based exits
|
||||||
|
3. **Manual**: No automatic selling
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExitStrategy(Enum):
|
||||||
|
TIME_BASED = "time_based"
|
||||||
|
TP_SL = "tp_sl"
|
||||||
|
MANUAL = "manual"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform Integration Rules
|
||||||
|
|
||||||
|
### Multi-Platform Support
|
||||||
|
- Use platform enum for type safety
|
||||||
|
- Implement platform-specific address providers
|
||||||
|
- Abstract platform differences in universal components
|
||||||
|
- Validate platform-listener combinations
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Platform validation
|
||||||
|
if not validate_platform_listener_combination(platform, listener_type):
|
||||||
|
supported = get_supported_listeners_for_platform(platform)
|
||||||
|
raise ConfigurationError(
|
||||||
|
f"Listener '{listener_type}' not supported for {platform.value}. "
|
||||||
|
f"Supported: {supported}"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Listener Types
|
||||||
|
Support multiple data source types:
|
||||||
|
- **geyser**: Fastest, requires special endpoint
|
||||||
|
- **logs**: WebSocket log subscription
|
||||||
|
- **blocks**: Block subscription (not all providers support)
|
||||||
|
- **pumpportal**: Third-party aggregator
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Speed vs Accuracy Tradeoffs
|
||||||
|
- **Extreme Fast Mode**: Skip validations and price checks for speed
|
||||||
|
- **Normal Mode**: Full validation and price checks
|
||||||
|
- **Marry Mode**: Only buy, never sell (accumulation strategy)
|
||||||
|
- **YOLO Mode**: Continuous trading without cooldowns
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
```python
|
||||||
|
# Cache expensive operations
|
||||||
|
self._cached_blockhash: Hash | None = None
|
||||||
|
self._blockhash_lock = asyncio.Lock()
|
||||||
|
|
||||||
|
# Background blockhash updater
|
||||||
|
async def start_blockhash_updater(self, interval: float = 5.0):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
blockhash = await self.get_latest_blockhash()
|
||||||
|
async with self._blockhash_lock:
|
||||||
|
self._cached_blockhash = blockhash
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to update blockhash: {e}")
|
||||||
|
await asyncio.sleep(interval)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Logging
|
||||||
|
|
||||||
|
### Log File Management
|
||||||
|
- Create timestamped log files per bot instance
|
||||||
|
- Format: `{bot_name}_{timestamp}.log`
|
||||||
|
- Store in `logs/` directory
|
||||||
|
- Implement log rotation for long-running bots
|
||||||
|
|
||||||
|
### Trading Event Logging
|
||||||
|
Log all significant events with context:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Good logging examples
|
||||||
|
logger.info(f"New token detected: {mint} by {creator}")
|
||||||
|
logger.info(f"Buy transaction submitted: {signature}")
|
||||||
|
logger.warning(f"Transaction failed, attempt {attempt}/{max_attempts}")
|
||||||
|
logger.error(f"Platform {platform.value} not supported")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Metrics
|
||||||
|
Track key performance indicators:
|
||||||
|
- Token detection latency
|
||||||
|
- Transaction confirmation time
|
||||||
|
- Success/failure rates
|
||||||
|
- Slippage and fill rates
|
||||||
|
|
||||||
|
## Security and Safety Rules
|
||||||
|
|
||||||
|
### Private Key Management
|
||||||
|
- Store private keys only in environment variables
|
||||||
|
- Never log or expose private keys
|
||||||
|
- Use separate wallets for testing vs production
|
||||||
|
- Implement wallet balance checks before trading
|
||||||
|
|
||||||
|
### Input Validation
|
||||||
|
```python
|
||||||
|
# Validate all external inputs
|
||||||
|
def validate_mint_address(mint_str: str) -> bool:
|
||||||
|
try:
|
||||||
|
mint = Pubkey.from_string(mint_str)
|
||||||
|
return len(str(mint)) == 44 # Valid Solana address length
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Recovery
|
||||||
|
- Implement graceful shutdown on critical errors
|
||||||
|
- Provide cleanup mechanisms for stuck positions
|
||||||
|
- Support manual intervention modes
|
||||||
|
- Log all errors with sufficient context for debugging
|
||||||
|
|
||||||
|
## Testing and Validation
|
||||||
|
|
||||||
|
### Learning Examples Usage
|
||||||
|
Use learning examples for:
|
||||||
|
- Testing new features before integration
|
||||||
|
- Validating platform-specific functionality
|
||||||
|
- Performance benchmarking
|
||||||
|
- Educational purposes for new developers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test platform connectivity
|
||||||
|
uv run learning-examples/fetch_price.py
|
||||||
|
|
||||||
|
# Validate bonding curve calculations
|
||||||
|
uv run learning-examples/compute_associated_bonding_curve.py
|
||||||
|
|
||||||
|
# Compare listener performance
|
||||||
|
uv run learning-examples/listen-new-tokens/compare_listeners.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Testing
|
||||||
|
- Validate YAML syntax and required fields
|
||||||
|
- Test environment variable interpolation
|
||||||
|
- Verify platform-listener compatibility
|
||||||
|
- Check wallet connectivity and balance
|
||||||
|
|
||||||
|
## Deployment Guidelines
|
||||||
|
|
||||||
|
### Production Checklist
|
||||||
|
1. Test configuration with learning examples
|
||||||
|
2. Verify environment variables are set
|
||||||
|
3. Check wallet has sufficient SOL for gas fees
|
||||||
|
4. Enable separate processes for isolation
|
||||||
|
5. Monitor logs for successful startup
|
||||||
|
6. Implement monitoring and alerting
|
||||||
|
|
||||||
|
### Multi-Bot Management
|
||||||
|
- Use descriptive bot names in configurations
|
||||||
|
- Separate log files per bot instance
|
||||||
|
- Monitor resource usage across all bots
|
||||||
|
- Implement centralized configuration management
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Bot process management
|
||||||
|
if cfg.get("separate_process", False):
|
||||||
|
p = multiprocessing.Process(
|
||||||
|
target=run_bot_process,
|
||||||
|
args=(str(file),),
|
||||||
|
name=f"bot-{bot_name}"
|
||||||
|
)
|
||||||
|
p.start()
|
||||||
|
processes.append(p)
|
||||||
|
```
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
inclusion: always
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project Architecture Rules
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
### Package Organization
|
||||||
|
Maintain clear separation of concerns:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── __init__.py
|
||||||
|
├── bot_runner.py # Main entry point
|
||||||
|
├── config_loader.py # Configuration management
|
||||||
|
├── core/ # Core blockchain functionality
|
||||||
|
│ ├── client.py # Solana RPC client abstraction
|
||||||
|
│ ├── wallet.py # Wallet operations
|
||||||
|
│ └── priority_fee/ # Fee management
|
||||||
|
├── platforms/ # Platform-specific implementations
|
||||||
|
│ ├── pumpfun/ # pump.fun specific code
|
||||||
|
│ └── letsbonk/ # letsbonk.fun specific code
|
||||||
|
├── trading/ # Trading logic
|
||||||
|
│ ├── base.py # Base trading classes
|
||||||
|
│ ├── universal_trader.py # Platform-agnostic trader
|
||||||
|
│ └── position.py # Position management
|
||||||
|
├── monitoring/ # Event listening and monitoring
|
||||||
|
│ ├── base_listener.py # Base listener interface
|
||||||
|
│ └── universal_*_listener.py # Specific listeners
|
||||||
|
├── interfaces/ # Abstract base classes
|
||||||
|
└── utils/ # Utilities and helpers
|
||||||
|
├── logger.py # Logging utilities
|
||||||
|
└── idl_manager.py # IDL management
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Naming Conventions
|
||||||
|
- Use snake_case for all Python files and directories
|
||||||
|
- Prefix abstract base classes with "Base" or put in `interfaces/`
|
||||||
|
- Use "Universal" prefix for platform-agnostic implementations
|
||||||
|
- Group related functionality in subdirectories
|
||||||
|
|
||||||
|
## Design Patterns
|
||||||
|
|
||||||
|
### Platform Abstraction
|
||||||
|
Implement platform-specific functionality using the factory pattern:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# interfaces/core.py - Define abstract interfaces
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
class AddressProvider(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def get_program_address(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# platforms/pumpfun/address_provider.py - Concrete implementation
|
||||||
|
class PumpFunAddressProvider(AddressProvider):
|
||||||
|
def get_program_address(self) -> str:
|
||||||
|
return "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Universal Components
|
||||||
|
Create platform-agnostic wrappers that delegate to platform-specific implementations:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class UniversalTrader:
|
||||||
|
def __init__(self, platform: Platform, **kwargs):
|
||||||
|
self.platform = platform
|
||||||
|
self.platform_trader = self._create_platform_trader()
|
||||||
|
|
||||||
|
def _create_platform_trader(self):
|
||||||
|
# Factory method to create platform-specific trader
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
- Use YAML files for bot configurations in `bots/` directory
|
||||||
|
- Support environment variable interpolation with `${VARIABLE}` syntax
|
||||||
|
- Validate configurations before starting bots
|
||||||
|
- Separate environment-specific settings in `.env` files
|
||||||
|
|
||||||
|
## Module Dependencies
|
||||||
|
|
||||||
|
### Import Rules
|
||||||
|
- Core modules should not import from trading or monitoring
|
||||||
|
- Platform-specific modules should only import from their own package and core/interfaces
|
||||||
|
- Avoid circular imports between packages
|
||||||
|
- Use dependency injection for cross-package dependencies
|
||||||
|
|
||||||
|
### Dependency Layers (from low to high level)
|
||||||
|
1. **utils/** - Utilities and helpers (no business logic dependencies)
|
||||||
|
2. **interfaces/** - Abstract base classes and protocols
|
||||||
|
3. **core/** - Blockchain and infrastructure (depends on utils, interfaces)
|
||||||
|
4. **platforms/** - Platform implementations (depends on core, interfaces)
|
||||||
|
5. **trading/** - Trading logic (depends on core, platforms, interfaces)
|
||||||
|
6. **monitoring/** - Event listening (depends on core, platforms, interfaces)
|
||||||
|
7. **bot_runner.py** - Main orchestrator (depends on all layers)
|
||||||
|
|
||||||
|
## Async Architecture
|
||||||
|
|
||||||
|
### Event Loop Management
|
||||||
|
- Use uvloop for better performance
|
||||||
|
- Set event loop policy at application startup
|
||||||
|
- Use asyncio.create_task() for concurrent operations
|
||||||
|
- Implement proper cleanup on shutdown
|
||||||
|
|
||||||
|
### Connection Management
|
||||||
|
- Use connection pooling for HTTP clients
|
||||||
|
- Implement reconnection logic for WebSocket connections
|
||||||
|
- Cache expensive resources (blockhash, account info)
|
||||||
|
- Use async context managers for resource cleanup
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
### Test Organization
|
||||||
|
- Use `learning-examples/` for integration testing and validation
|
||||||
|
- Test platform-specific components independently
|
||||||
|
- Mock external dependencies (RPC calls, WebSocket connections)
|
||||||
|
- Validate configurations with actual bot startup
|
||||||
|
|
||||||
|
### Test Data
|
||||||
|
- Use test networks for development
|
||||||
|
- Never test with real funds or production keys
|
||||||
|
- Create fixtures for common test scenarios
|
||||||
|
- Document test account requirements
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
- Cache recent blockhash in background task
|
||||||
|
- Cache account information where appropriate
|
||||||
|
- Use local caching for IDL data
|
||||||
|
- Implement TTL for cached data
|
||||||
|
|
||||||
|
### Resource Management
|
||||||
|
- Limit concurrent operations based on RPC provider limits
|
||||||
|
- Implement backoff strategies for failed requests
|
||||||
|
- Use separate processes for production bot instances
|
||||||
|
- Monitor memory usage in long-running processes
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
inclusion: always
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python Code Style Rules
|
||||||
|
|
||||||
|
## Formatting Standards
|
||||||
|
|
||||||
|
### Ruff Configuration Compliance
|
||||||
|
- Use 88 character line length limit
|
||||||
|
- Use 4 spaces for indentation (never tabs)
|
||||||
|
- Use double quotes for strings consistently
|
||||||
|
- Target Python 3.11+ features and syntax
|
||||||
|
- Enable automatic import sorting and organization
|
||||||
|
|
||||||
|
### Import Organization
|
||||||
|
```python
|
||||||
|
# Standard library imports first
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Third-party imports second
|
||||||
|
import aiohttp
|
||||||
|
from solana.rpc.async_api import AsyncClient
|
||||||
|
|
||||||
|
# Local imports last
|
||||||
|
from config_loader import load_bot_config
|
||||||
|
from utils.logger import get_logger
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type Annotations
|
||||||
|
- Add type hints to ALL public functions and methods
|
||||||
|
- Use modern typing syntax (Python 3.9+ union syntax where applicable)
|
||||||
|
- Include return type annotations
|
||||||
|
- Use `from typing import Any` for complex types
|
||||||
|
|
||||||
|
```python
|
||||||
|
def process_transaction(tx_data: dict[str, Any]) -> bool:
|
||||||
|
"""Process transaction data and return success status."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def fetch_data(endpoint: str) -> dict[str, Any] | None:
|
||||||
|
"""Fetch data from endpoint, return None on failure."""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation Standards
|
||||||
|
|
||||||
|
### Docstring Format
|
||||||
|
Use Google-style docstrings for all functions and classes:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def calculate_slippage(amount: float, slippage_percent: float) -> float:
|
||||||
|
"""Calculate slippage amount for a trade.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
amount: The trade amount in SOL
|
||||||
|
slippage_percent: Slippage percentage (0.1 = 10%)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The calculated slippage amount
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If slippage_percent is negative
|
||||||
|
"""
|
||||||
|
if slippage_percent < 0:
|
||||||
|
raise ValueError("Slippage percentage cannot be negative")
|
||||||
|
return amount * slippage_percent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Comprehensive Exception Handling
|
||||||
|
- Use try-catch blocks for all external operations (RPC calls, file I/O)
|
||||||
|
- Log exceptions with context using `logging.exception()`
|
||||||
|
- Provide meaningful error messages
|
||||||
|
- Don't suppress exceptions without good reason
|
||||||
|
|
||||||
|
```python
|
||||||
|
try:
|
||||||
|
result = await client.get_account_info(address)
|
||||||
|
logger.info(f"Successfully fetched account info for {address}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to fetch account info for {address}: {e}")
|
||||||
|
raise
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging Standards
|
||||||
|
|
||||||
|
### Logger Usage
|
||||||
|
- Use `get_logger(__name__)` pattern consistently
|
||||||
|
- Import from `utils.logger`
|
||||||
|
- Use appropriate log levels (DEBUG, INFO, WARNING, ERROR)
|
||||||
|
- Include context in log messages
|
||||||
|
|
||||||
|
```python
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
# Good logging examples
|
||||||
|
logger.info(f"Starting bot '{bot_name}' with platform {platform.value}")
|
||||||
|
logger.warning(f"Transaction failed, attempt {attempt}/{max_attempts}")
|
||||||
|
logger.error(f"Platform {platform.value} is not supported")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Rules
|
||||||
|
|
||||||
|
### Sensitive Data
|
||||||
|
- NEVER hardcode private keys, API tokens, or secrets
|
||||||
|
- Use environment variables for all sensitive configuration
|
||||||
|
- Don't log sensitive information
|
||||||
|
- Validate all external inputs
|
||||||
|
|
||||||
|
### Safe Practices
|
||||||
|
```python
|
||||||
|
# Good - using environment variables
|
||||||
|
private_key = os.getenv("SOLANA_PRIVATE_KEY")
|
||||||
|
if not private_key:
|
||||||
|
raise ValueError("SOLANA_PRIVATE_KEY environment variable is required")
|
||||||
|
|
||||||
|
# Bad - hardcoded secrets
|
||||||
|
private_key = "your_secret_key_here" # NEVER DO THIS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Quality
|
||||||
|
|
||||||
|
### Linting Compliance
|
||||||
|
Ensure code passes all enabled Ruff rules:
|
||||||
|
- Security best practices (S)
|
||||||
|
- Type annotations (ANN)
|
||||||
|
- Exception handling (BLE, TRY)
|
||||||
|
- Code complexity (C90)
|
||||||
|
- Pylint conventions (PL)
|
||||||
|
- No commented-out code (ERA)
|
||||||
|
|
||||||
|
### Performance Considerations
|
||||||
|
- Use async/await for I/O operations
|
||||||
|
- Implement proper connection pooling for HTTP clients
|
||||||
|
- Cache expensive computations when appropriate
|
||||||
|
- Use uvloop for better async performance
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Set uvloop policy at module level
|
||||||
|
import asyncio
|
||||||
|
import uvloop
|
||||||
|
|
||||||
|
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||||
|
```
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
---
|
||||||
|
inclusion: always
|
||||||
|
---
|
||||||
|
|
||||||
|
# Trading Bot Specific Rules
|
||||||
|
|
||||||
|
## Bot Configuration Standards
|
||||||
|
|
||||||
|
### YAML Configuration Structure
|
||||||
|
Maintain consistent structure across all bot configuration files:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Bot identification
|
||||||
|
name: "bot-sniper-1"
|
||||||
|
platform: "pump_fun" # or "lets_bonk"
|
||||||
|
enabled: true # Allow disabling without removing config
|
||||||
|
separate_process: true # Run in separate process for isolation
|
||||||
|
|
||||||
|
# Environment and connection
|
||||||
|
env_file: ".env"
|
||||||
|
rpc_endpoint: "${SOLANA_NODE_RPC_ENDPOINT}"
|
||||||
|
wss_endpoint: "${SOLANA_NODE_WSS_ENDPOINT}"
|
||||||
|
private_key: "${SOLANA_PRIVATE_KEY}"
|
||||||
|
|
||||||
|
# Platform-specific configurations
|
||||||
|
geyser: # For faster data streams
|
||||||
|
endpoint: "${GEYSER_ENDPOINT}"
|
||||||
|
api_token: "${GEYSER_API_TOKEN}"
|
||||||
|
auth_type: "x-token"
|
||||||
|
|
||||||
|
# Trading parameters
|
||||||
|
trade:
|
||||||
|
buy_amount: 0.0001 # SOL amount
|
||||||
|
buy_slippage: 0.3 # 30%
|
||||||
|
sell_slippage: 0.3
|
||||||
|
exit_strategy: "time_based" # "tp_sl", "manual"
|
||||||
|
extreme_fast_mode: true # Skip validations for speed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variable Usage
|
||||||
|
- Use `${VARIABLE_NAME}` syntax for environment interpolation
|
||||||
|
- Never hardcode sensitive values in YAML files
|
||||||
|
- Validate all required environment variables on startup
|
||||||
|
- Provide clear error messages for missing variables
|
||||||
|
|
||||||
|
## Trading Logic Rules
|
||||||
|
|
||||||
|
### Transaction Handling
|
||||||
|
- Always use priority fees for competitive transaction inclusion
|
||||||
|
- Implement retry mechanisms with exponential backoff
|
||||||
|
- Cache recent blockhash to avoid repeated RPC calls
|
||||||
|
- Use compute unit limits to prevent transaction failures
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Good transaction building pattern
|
||||||
|
instructions = [
|
||||||
|
set_compute_unit_limit(300_000),
|
||||||
|
set_compute_unit_price(priority_fee),
|
||||||
|
# ... trading instructions
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Risk Management
|
||||||
|
- Implement position size limits
|
||||||
|
- Use slippage protection on all trades
|
||||||
|
- Set maximum hold times to prevent stuck positions
|
||||||
|
- Validate token data before trading
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Risk validation example
|
||||||
|
if token_age > self.max_token_age:
|
||||||
|
logger.warning(f"Token {mint} too old ({token_age}s), skipping")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if buy_amount > self.max_position_size:
|
||||||
|
logger.error(f"Buy amount {buy_amount} exceeds max position size")
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exit Strategies
|
||||||
|
Implement multiple exit strategy types:
|
||||||
|
|
||||||
|
1. **Time-based**: Hold for fixed duration
|
||||||
|
2. **Take Profit/Stop Loss**: Price-based exits
|
||||||
|
3. **Manual**: No automatic selling
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExitStrategy(Enum):
|
||||||
|
TIME_BASED = "time_based"
|
||||||
|
TP_SL = "tp_sl"
|
||||||
|
MANUAL = "manual"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform Integration Rules
|
||||||
|
|
||||||
|
### Multi-Platform Support
|
||||||
|
- Use platform enum for type safety
|
||||||
|
- Implement platform-specific address providers
|
||||||
|
- Abstract platform differences in universal components
|
||||||
|
- Validate platform-listener combinations
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Platform validation
|
||||||
|
if not validate_platform_listener_combination(platform, listener_type):
|
||||||
|
supported = get_supported_listeners_for_platform(platform)
|
||||||
|
raise ConfigurationError(
|
||||||
|
f"Listener '{listener_type}' not supported for {platform.value}. "
|
||||||
|
f"Supported: {supported}"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Listener Types
|
||||||
|
Support multiple data source types:
|
||||||
|
- **geyser**: Fastest, requires special endpoint
|
||||||
|
- **logs**: WebSocket log subscription
|
||||||
|
- **blocks**: Block subscription (not all providers support)
|
||||||
|
- **pumpportal**: Third-party aggregator
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Speed vs Accuracy Tradeoffs
|
||||||
|
- **Extreme Fast Mode**: Skip validations and price checks for speed
|
||||||
|
- **Normal Mode**: Full validation and price checks
|
||||||
|
- **Marry Mode**: Only buy, never sell (accumulation strategy)
|
||||||
|
- **YOLO Mode**: Continuous trading without cooldowns
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
```python
|
||||||
|
# Cache expensive operations
|
||||||
|
self._cached_blockhash: Hash | None = None
|
||||||
|
self._blockhash_lock = asyncio.Lock()
|
||||||
|
|
||||||
|
# Background blockhash updater
|
||||||
|
async def start_blockhash_updater(self, interval: float = 5.0):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
blockhash = await self.get_latest_blockhash()
|
||||||
|
async with self._blockhash_lock:
|
||||||
|
self._cached_blockhash = blockhash
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to update blockhash: {e}")
|
||||||
|
await asyncio.sleep(interval)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Logging
|
||||||
|
|
||||||
|
### Log File Management
|
||||||
|
- Create timestamped log files per bot instance
|
||||||
|
- Format: `{bot_name}_{timestamp}.log`
|
||||||
|
- Store in `logs/` directory
|
||||||
|
- Implement log rotation for long-running bots
|
||||||
|
|
||||||
|
### Trading Event Logging
|
||||||
|
Log all significant events with context:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Good logging examples
|
||||||
|
logger.info(f"New token detected: {mint} by {creator}")
|
||||||
|
logger.info(f"Buy transaction submitted: {signature}")
|
||||||
|
logger.warning(f"Transaction failed, attempt {attempt}/{max_attempts}")
|
||||||
|
logger.error(f"Platform {platform.value} not supported")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Metrics
|
||||||
|
Track key performance indicators:
|
||||||
|
- Token detection latency
|
||||||
|
- Transaction confirmation time
|
||||||
|
- Success/failure rates
|
||||||
|
- Slippage and fill rates
|
||||||
|
|
||||||
|
## Security and Safety Rules
|
||||||
|
|
||||||
|
### Private Key Management
|
||||||
|
- Store private keys only in environment variables
|
||||||
|
- Never log or expose private keys
|
||||||
|
- Use separate wallets for testing vs production
|
||||||
|
- Implement wallet balance checks before trading
|
||||||
|
|
||||||
|
### Input Validation
|
||||||
|
```python
|
||||||
|
# Validate all external inputs
|
||||||
|
def validate_mint_address(mint_str: str) -> bool:
|
||||||
|
try:
|
||||||
|
mint = Pubkey.from_string(mint_str)
|
||||||
|
return len(str(mint)) == 44 # Valid Solana address length
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Recovery
|
||||||
|
- Implement graceful shutdown on critical errors
|
||||||
|
- Provide cleanup mechanisms for stuck positions
|
||||||
|
- Support manual intervention modes
|
||||||
|
- Log all errors with sufficient context for debugging
|
||||||
|
|
||||||
|
## Testing and Validation
|
||||||
|
|
||||||
|
### Learning Examples Usage
|
||||||
|
Use learning examples for:
|
||||||
|
- Testing new features before integration
|
||||||
|
- Validating platform-specific functionality
|
||||||
|
- Performance benchmarking
|
||||||
|
- Educational purposes for new developers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test platform connectivity
|
||||||
|
uv run learning-examples/fetch_price.py
|
||||||
|
|
||||||
|
# Validate bonding curve calculations
|
||||||
|
uv run learning-examples/compute_associated_bonding_curve.py
|
||||||
|
|
||||||
|
# Compare listener performance
|
||||||
|
uv run learning-examples/listen-new-tokens/compare_listeners.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Testing
|
||||||
|
- Validate YAML syntax and required fields
|
||||||
|
- Test environment variable interpolation
|
||||||
|
- Verify platform-listener compatibility
|
||||||
|
- Check wallet connectivity and balance
|
||||||
|
|
||||||
|
## Deployment Guidelines
|
||||||
|
|
||||||
|
### Production Checklist
|
||||||
|
1. Test configuration with learning examples
|
||||||
|
2. Verify environment variables are set
|
||||||
|
3. Check wallet has sufficient SOL for gas fees
|
||||||
|
4. Enable separate processes for isolation
|
||||||
|
5. Monitor logs for successful startup
|
||||||
|
6. Implement monitoring and alerting
|
||||||
|
|
||||||
|
### Multi-Bot Management
|
||||||
|
- Use descriptive bot names in configurations
|
||||||
|
- Separate log files per bot instance
|
||||||
|
- Monitor resource usage across all bots
|
||||||
|
- Implement centralized configuration management
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Bot process management
|
||||||
|
if cfg.get("separate_process", False):
|
||||||
|
p = multiprocessing.Process(
|
||||||
|
target=run_bot_process,
|
||||||
|
args=(str(file),),
|
||||||
|
name=f"bot-{bot_name}"
|
||||||
|
)
|
||||||
|
p.start()
|
||||||
|
processes.append(p)
|
||||||
|
```
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
trigger: always_on
|
||||||
|
---
|
||||||
|
|
||||||
|
# Project Architecture Rules
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
### Package Organization
|
||||||
|
Maintain clear separation of concerns:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── __init__.py
|
||||||
|
├── bot_runner.py # Main entry point
|
||||||
|
├── config_loader.py # Configuration management
|
||||||
|
├── core/ # Core blockchain functionality
|
||||||
|
│ ├── client.py # Solana RPC client abstraction
|
||||||
|
│ ├── wallet.py # Wallet operations
|
||||||
|
│ └── priority_fee/ # Fee management
|
||||||
|
├── platforms/ # Platform-specific implementations
|
||||||
|
│ ├── pumpfun/ # pump.fun specific code
|
||||||
|
│ └── letsbonk/ # letsbonk.fun specific code
|
||||||
|
├── trading/ # Trading logic
|
||||||
|
│ ├── base.py # Base trading classes
|
||||||
|
│ ├── universal_trader.py # Platform-agnostic trader
|
||||||
|
│ └── position.py # Position management
|
||||||
|
├── monitoring/ # Event listening and monitoring
|
||||||
|
│ ├── base_listener.py # Base listener interface
|
||||||
|
│ └── universal_*_listener.py # Specific listeners
|
||||||
|
├── interfaces/ # Abstract base classes
|
||||||
|
└── utils/ # Utilities and helpers
|
||||||
|
├── logger.py # Logging utilities
|
||||||
|
└── idl_manager.py # IDL management
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Naming Conventions
|
||||||
|
- Use snake_case for all Python files and directories
|
||||||
|
- Prefix abstract base classes with "Base" or put in `interfaces/`
|
||||||
|
- Use "Universal" prefix for platform-agnostic implementations
|
||||||
|
- Group related functionality in subdirectories
|
||||||
|
|
||||||
|
## Design Patterns
|
||||||
|
|
||||||
|
### Platform Abstraction
|
||||||
|
Implement platform-specific functionality using the factory pattern:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# interfaces/core.py - Define abstract interfaces
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
class AddressProvider(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def get_program_address(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# platforms/pumpfun/address_provider.py - Concrete implementation
|
||||||
|
class PumpFunAddressProvider(AddressProvider):
|
||||||
|
def get_program_address(self) -> str:
|
||||||
|
return "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Universal Components
|
||||||
|
Create platform-agnostic wrappers that delegate to platform-specific implementations:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class UniversalTrader:
|
||||||
|
def __init__(self, platform: Platform, **kwargs):
|
||||||
|
self.platform = platform
|
||||||
|
self.platform_trader = self._create_platform_trader()
|
||||||
|
|
||||||
|
def _create_platform_trader(self):
|
||||||
|
# Factory method to create platform-specific trader
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
- Use YAML files for bot configurations in `bots/` directory
|
||||||
|
- Support environment variable interpolation with `${VARIABLE}` syntax
|
||||||
|
- Validate configurations before starting bots
|
||||||
|
- Separate environment-specific settings in `.env` files
|
||||||
|
|
||||||
|
## Module Dependencies
|
||||||
|
|
||||||
|
### Import Rules
|
||||||
|
- Core modules should not import from trading or monitoring
|
||||||
|
- Platform-specific modules should only import from their own package and core/interfaces
|
||||||
|
- Avoid circular imports between packages
|
||||||
|
- Use dependency injection for cross-package dependencies
|
||||||
|
|
||||||
|
### Dependency Layers (from low to high level)
|
||||||
|
1. **utils/** - Utilities and helpers (no business logic dependencies)
|
||||||
|
2. **interfaces/** - Abstract base classes and protocols
|
||||||
|
3. **core/** - Blockchain and infrastructure (depends on utils, interfaces)
|
||||||
|
4. **platforms/** - Platform implementations (depends on core, interfaces)
|
||||||
|
5. **trading/** - Trading logic (depends on core, platforms, interfaces)
|
||||||
|
6. **monitoring/** - Event listening (depends on core, platforms, interfaces)
|
||||||
|
7. **bot_runner.py** - Main orchestrator (depends on all layers)
|
||||||
|
|
||||||
|
## Async Architecture
|
||||||
|
|
||||||
|
### Event Loop Management
|
||||||
|
- Use uvloop for better performance
|
||||||
|
- Set event loop policy at application startup
|
||||||
|
- Use asyncio.create_task() for concurrent operations
|
||||||
|
- Implement proper cleanup on shutdown
|
||||||
|
|
||||||
|
### Connection Management
|
||||||
|
- Use connection pooling for HTTP clients
|
||||||
|
- Implement reconnection logic for WebSocket connections
|
||||||
|
- Cache expensive resources (blockhash, account info)
|
||||||
|
- Use async context managers for resource cleanup
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
### Test Organization
|
||||||
|
- Use `learning-examples/` for integration testing and validation
|
||||||
|
- Test platform-specific components independently
|
||||||
|
- Mock external dependencies (RPC calls, WebSocket connections)
|
||||||
|
- Validate configurations with actual bot startup
|
||||||
|
|
||||||
|
### Test Data
|
||||||
|
- Use test networks for development
|
||||||
|
- Never test with real funds or production keys
|
||||||
|
- Create fixtures for common test scenarios
|
||||||
|
- Document test account requirements
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
- Cache recent blockhash in background task
|
||||||
|
- Cache account information where appropriate
|
||||||
|
- Use local caching for IDL data
|
||||||
|
- Implement TTL for cached data
|
||||||
|
|
||||||
|
### Resource Management
|
||||||
|
- Limit concurrent operations based on RPC provider limits
|
||||||
|
- Implement backoff strategies for failed requests
|
||||||
|
- Use separate processes for production bot instances
|
||||||
|
- Monitor memory usage in long-running processes
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
trigger: always_on
|
||||||
|
---
|
||||||
|
|
||||||
|
# Python Code Style Rules
|
||||||
|
|
||||||
|
## Formatting Standards
|
||||||
|
|
||||||
|
### Ruff Configuration Compliance
|
||||||
|
- Use 88 character line length limit
|
||||||
|
- Use 4 spaces for indentation (never tabs)
|
||||||
|
- Use double quotes for strings consistently
|
||||||
|
- Target Python 3.11+ features and syntax
|
||||||
|
- Enable automatic import sorting and organization
|
||||||
|
|
||||||
|
### Import Organization
|
||||||
|
```python
|
||||||
|
# Standard library imports first
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Third-party imports second
|
||||||
|
import aiohttp
|
||||||
|
from solana.rpc.async_api import AsyncClient
|
||||||
|
|
||||||
|
# Local imports last
|
||||||
|
from config_loader import load_bot_config
|
||||||
|
from utils.logger import get_logger
|
||||||
|
```
|
||||||
|
|
||||||
|
### Type Annotations
|
||||||
|
- Add type hints to ALL public functions and methods
|
||||||
|
- Use modern typing syntax (Python 3.9+ union syntax where applicable)
|
||||||
|
- Include return type annotations
|
||||||
|
- Use `from typing import Any` for complex types
|
||||||
|
|
||||||
|
```python
|
||||||
|
def process_transaction(tx_data: dict[str, Any]) -> bool:
|
||||||
|
"""Process transaction data and return success status."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def fetch_data(endpoint: str) -> dict[str, Any] | None:
|
||||||
|
"""Fetch data from endpoint, return None on failure."""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation Standards
|
||||||
|
|
||||||
|
### Docstring Format
|
||||||
|
Use Google-style docstrings for all functions and classes:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def calculate_slippage(amount: float, slippage_percent: float) -> float:
|
||||||
|
"""Calculate slippage amount for a trade.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
amount: The trade amount in SOL
|
||||||
|
slippage_percent: Slippage percentage (0.1 = 10%)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The calculated slippage amount
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If slippage_percent is negative
|
||||||
|
"""
|
||||||
|
if slippage_percent < 0:
|
||||||
|
raise ValueError("Slippage percentage cannot be negative")
|
||||||
|
return amount * slippage_percent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Comprehensive Exception Handling
|
||||||
|
- Use try-catch blocks for all external operations (RPC calls, file I/O)
|
||||||
|
- Log exceptions with context using `logging.exception()`
|
||||||
|
- Provide meaningful error messages
|
||||||
|
- Don't suppress exceptions without good reason
|
||||||
|
|
||||||
|
```python
|
||||||
|
try:
|
||||||
|
result = await client.get_account_info(address)
|
||||||
|
logger.info(f"Successfully fetched account info for {address}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to fetch account info for {address}: {e}")
|
||||||
|
raise
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging Standards
|
||||||
|
|
||||||
|
### Logger Usage
|
||||||
|
- Use `get_logger(__name__)` pattern consistently
|
||||||
|
- Import from `utils.logger`
|
||||||
|
- Use appropriate log levels (DEBUG, INFO, WARNING, ERROR)
|
||||||
|
- Include context in log messages
|
||||||
|
|
||||||
|
```python
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
# Good logging examples
|
||||||
|
logger.info(f"Starting bot '{bot_name}' with platform {platform.value}")
|
||||||
|
logger.warning(f"Transaction failed, attempt {attempt}/{max_attempts}")
|
||||||
|
logger.error(f"Platform {platform.value} is not supported")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Rules
|
||||||
|
|
||||||
|
### Sensitive Data
|
||||||
|
- NEVER hardcode private keys, API tokens, or secrets
|
||||||
|
- Use environment variables for all sensitive configuration
|
||||||
|
- Don't log sensitive information
|
||||||
|
- Validate all external inputs
|
||||||
|
|
||||||
|
### Safe Practices
|
||||||
|
```python
|
||||||
|
# Good - using environment variables
|
||||||
|
private_key = os.getenv("SOLANA_PRIVATE_KEY")
|
||||||
|
if not private_key:
|
||||||
|
raise ValueError("SOLANA_PRIVATE_KEY environment variable is required")
|
||||||
|
|
||||||
|
# Bad - hardcoded secrets
|
||||||
|
private_key = "your_secret_key_here" # NEVER DO THIS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Quality
|
||||||
|
|
||||||
|
### Linting Compliance
|
||||||
|
Ensure code passes all enabled Ruff rules:
|
||||||
|
- Security best practices (S)
|
||||||
|
- Type annotations (ANN)
|
||||||
|
- Exception handling (BLE, TRY)
|
||||||
|
- Code complexity (C90)
|
||||||
|
- Pylint conventions (PL)
|
||||||
|
- No commented-out code (ERA)
|
||||||
|
|
||||||
|
### Performance Considerations
|
||||||
|
- Use async/await for I/O operations
|
||||||
|
- Implement proper connection pooling for HTTP clients
|
||||||
|
- Cache expensive computations when appropriate
|
||||||
|
- Use uvloop for better async performance
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Set uvloop policy at module level
|
||||||
|
import asyncio
|
||||||
|
import uvloop
|
||||||
|
|
||||||
|
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||||
|
```
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
---
|
||||||
|
trigger: always_on
|
||||||
|
---
|
||||||
|
|
||||||
|
# Trading Bot Specific Rules
|
||||||
|
|
||||||
|
## Bot Configuration Standards
|
||||||
|
|
||||||
|
### YAML Configuration Structure
|
||||||
|
Maintain consistent structure across all bot configuration files:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Bot identification
|
||||||
|
name: "bot-sniper-1"
|
||||||
|
platform: "pump_fun" # or "lets_bonk"
|
||||||
|
enabled: true # Allow disabling without removing config
|
||||||
|
separate_process: true # Run in separate process for isolation
|
||||||
|
|
||||||
|
# Environment and connection
|
||||||
|
env_file: ".env"
|
||||||
|
rpc_endpoint: "${SOLANA_NODE_RPC_ENDPOINT}"
|
||||||
|
wss_endpoint: "${SOLANA_NODE_WSS_ENDPOINT}"
|
||||||
|
private_key: "${SOLANA_PRIVATE_KEY}"
|
||||||
|
|
||||||
|
# Platform-specific configurations
|
||||||
|
geyser: # For faster data streams
|
||||||
|
endpoint: "${GEYSER_ENDPOINT}"
|
||||||
|
api_token: "${GEYSER_API_TOKEN}"
|
||||||
|
auth_type: "x-token"
|
||||||
|
|
||||||
|
# Trading parameters
|
||||||
|
trade:
|
||||||
|
buy_amount: 0.0001 # SOL amount
|
||||||
|
buy_slippage: 0.3 # 30%
|
||||||
|
sell_slippage: 0.3
|
||||||
|
exit_strategy: "time_based" # "tp_sl", "manual"
|
||||||
|
extreme_fast_mode: true # Skip validations for speed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variable Usage
|
||||||
|
- Use `${VARIABLE_NAME}` syntax for environment interpolation
|
||||||
|
- Never hardcode sensitive values in YAML files
|
||||||
|
- Validate all required environment variables on startup
|
||||||
|
- Provide clear error messages for missing variables
|
||||||
|
|
||||||
|
## Trading Logic Rules
|
||||||
|
|
||||||
|
### Transaction Handling
|
||||||
|
- Always use priority fees for competitive transaction inclusion
|
||||||
|
- Implement retry mechanisms with exponential backoff
|
||||||
|
- Cache recent blockhash to avoid repeated RPC calls
|
||||||
|
- Use compute unit limits to prevent transaction failures
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Good transaction building pattern
|
||||||
|
instructions = [
|
||||||
|
set_compute_unit_limit(300_000),
|
||||||
|
set_compute_unit_price(priority_fee),
|
||||||
|
# ... trading instructions
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Risk Management
|
||||||
|
- Implement position size limits
|
||||||
|
- Use slippage protection on all trades
|
||||||
|
- Set maximum hold times to prevent stuck positions
|
||||||
|
- Validate token data before trading
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Risk validation example
|
||||||
|
if token_age > self.max_token_age:
|
||||||
|
logger.warning(f"Token {mint} too old ({token_age}s), skipping")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if buy_amount > self.max_position_size:
|
||||||
|
logger.error(f"Buy amount {buy_amount} exceeds max position size")
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exit Strategies
|
||||||
|
Implement multiple exit strategy types:
|
||||||
|
|
||||||
|
1. **Time-based**: Hold for fixed duration
|
||||||
|
2. **Take Profit/Stop Loss**: Price-based exits
|
||||||
|
3. **Manual**: No automatic selling
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExitStrategy(Enum):
|
||||||
|
TIME_BASED = "time_based"
|
||||||
|
TP_SL = "tp_sl"
|
||||||
|
MANUAL = "manual"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform Integration Rules
|
||||||
|
|
||||||
|
### Multi-Platform Support
|
||||||
|
- Use platform enum for type safety
|
||||||
|
- Implement platform-specific address providers
|
||||||
|
- Abstract platform differences in universal components
|
||||||
|
- Validate platform-listener combinations
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Platform validation
|
||||||
|
if not validate_platform_listener_combination(platform, listener_type):
|
||||||
|
supported = get_supported_listeners_for_platform(platform)
|
||||||
|
raise ConfigurationError(
|
||||||
|
f"Listener '{listener_type}' not supported for {platform.value}. "
|
||||||
|
f"Supported: {supported}"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Listener Types
|
||||||
|
Support multiple data source types:
|
||||||
|
- **geyser**: Fastest, requires special endpoint
|
||||||
|
- **logs**: WebSocket log subscription
|
||||||
|
- **blocks**: Block subscription (not all providers support)
|
||||||
|
- **pumpportal**: Third-party aggregator
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Speed vs Accuracy Tradeoffs
|
||||||
|
- **Extreme Fast Mode**: Skip validations and price checks for speed
|
||||||
|
- **Normal Mode**: Full validation and price checks
|
||||||
|
- **Marry Mode**: Only buy, never sell (accumulation strategy)
|
||||||
|
- **YOLO Mode**: Continuous trading without cooldowns
|
||||||
|
|
||||||
|
### Caching Strategy
|
||||||
|
```python
|
||||||
|
# Cache expensive operations
|
||||||
|
self._cached_blockhash: Hash | None = None
|
||||||
|
self._blockhash_lock = asyncio.Lock()
|
||||||
|
|
||||||
|
# Background blockhash updater
|
||||||
|
async def start_blockhash_updater(self, interval: float = 5.0):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
blockhash = await self.get_latest_blockhash()
|
||||||
|
async with self._blockhash_lock:
|
||||||
|
self._cached_blockhash = blockhash
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(f"Failed to update blockhash: {e}")
|
||||||
|
await asyncio.sleep(interval)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring and Logging
|
||||||
|
|
||||||
|
### Log File Management
|
||||||
|
- Create timestamped log files per bot instance
|
||||||
|
- Format: `{bot_name}_{timestamp}.log`
|
||||||
|
- Store in `logs/` directory
|
||||||
|
- Implement log rotation for long-running bots
|
||||||
|
|
||||||
|
### Trading Event Logging
|
||||||
|
Log all significant events with context:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Good logging examples
|
||||||
|
logger.info(f"New token detected: {mint} by {creator}")
|
||||||
|
logger.info(f"Buy transaction submitted: {signature}")
|
||||||
|
logger.warning(f"Transaction failed, attempt {attempt}/{max_attempts}")
|
||||||
|
logger.error(f"Platform {platform.value} not supported")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Metrics
|
||||||
|
Track key performance indicators:
|
||||||
|
- Token detection latency
|
||||||
|
- Transaction confirmation time
|
||||||
|
- Success/failure rates
|
||||||
|
- Slippage and fill rates
|
||||||
|
|
||||||
|
## Security and Safety Rules
|
||||||
|
|
||||||
|
### Private Key Management
|
||||||
|
- Store private keys only in environment variables
|
||||||
|
- Never log or expose private keys
|
||||||
|
- Use separate wallets for testing vs production
|
||||||
|
- Implement wallet balance checks before trading
|
||||||
|
|
||||||
|
### Input Validation
|
||||||
|
```python
|
||||||
|
# Validate all external inputs
|
||||||
|
def validate_mint_address(mint_str: str) -> bool:
|
||||||
|
try:
|
||||||
|
mint = Pubkey.from_string(mint_str)
|
||||||
|
return len(str(mint)) == 44 # Valid Solana address length
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Recovery
|
||||||
|
- Implement graceful shutdown on critical errors
|
||||||
|
- Provide cleanup mechanisms for stuck positions
|
||||||
|
- Support manual intervention modes
|
||||||
|
- Log all errors with sufficient context for debugging
|
||||||
|
|
||||||
|
## Testing and Validation
|
||||||
|
|
||||||
|
### Learning Examples Usage
|
||||||
|
Use learning examples for:
|
||||||
|
- Testing new features before integration
|
||||||
|
- Validating platform-specific functionality
|
||||||
|
- Performance benchmarking
|
||||||
|
- Educational purposes for new developers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test platform connectivity
|
||||||
|
uv run learning-examples/fetch_price.py
|
||||||
|
|
||||||
|
# Validate bonding curve calculations
|
||||||
|
uv run learning-examples/compute_associated_bonding_curve.py
|
||||||
|
|
||||||
|
# Compare listener performance
|
||||||
|
uv run learning-examples/listen-new-tokens/compare_listeners.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Testing
|
||||||
|
- Validate YAML syntax and required fields
|
||||||
|
- Test environment variable interpolation
|
||||||
|
- Verify platform-listener compatibility
|
||||||
|
- Check wallet connectivity and balance
|
||||||
|
|
||||||
|
## Deployment Guidelines
|
||||||
|
|
||||||
|
### Production Checklist
|
||||||
|
1. Test configuration with learning examples
|
||||||
|
2. Verify environment variables are set
|
||||||
|
3. Check wallet has sufficient SOL for gas fees
|
||||||
|
4. Enable separate processes for isolation
|
||||||
|
5. Monitor logs for successful startup
|
||||||
|
6. Implement monitoring and alerting
|
||||||
|
|
||||||
|
### Multi-Bot Management
|
||||||
|
- Use descriptive bot names in configurations
|
||||||
|
- Separate log files per bot instance
|
||||||
|
- Monitor resource usage across all bots
|
||||||
|
- Implement centralized configuration management
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Bot process management
|
||||||
|
if cfg.get("separate_process", False):
|
||||||
|
p = multiprocessing.Process(
|
||||||
|
target=run_bot_process,
|
||||||
|
args=(str(file),),
|
||||||
|
name=f"bot-{bot_name}"
|
||||||
|
)
|
||||||
|
p.start()
|
||||||
|
processes.append(p)
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user