diff --git a/bots/bot-sniper-1-geyser.yaml b/bots/bot-sniper-1-geyser.yaml index ec05ef4..1346d8c 100644 --- a/bots/bot-sniper-1-geyser.yaml +++ b/bots/bot-sniper-1-geyser.yaml @@ -50,6 +50,13 @@ priority_fees: extra_percentage: 0.0 # Percentage increase on riority fee regardless of the calculation method (0.1 = 10%) hard_cap: 1_000_000 # Maximum allowable fee in microlamports to prevent excessive spending +# Compute unit limits for transaction processing +# Operation-specific defaults are used if not specified: buy=100K, sell=60K +compute_units: + # Override default CU limits for this platform + # buy: 100_000 # Buy operations (ATA creation + trading) + # sell: 60_000 # Sell operations (just trading) + # Filters for token selection filters: match_string: null # Only process tokens with this string in name/symbol diff --git a/bots/bot-sniper-2-logs.yaml b/bots/bot-sniper-2-logs.yaml index 259084d..0283b25 100644 --- a/bots/bot-sniper-2-logs.yaml +++ b/bots/bot-sniper-2-logs.yaml @@ -8,7 +8,7 @@ rpc_endpoint: "${SOLANA_NODE_RPC_ENDPOINT}" wss_endpoint: "${SOLANA_NODE_WSS_ENDPOINT}" private_key: "${SOLANA_PRIVATE_KEY}" -enabled: true # You can turn off the bot w/o removing its config +enabled: false # You can turn off the bot w/o removing its config separate_process: true # Options: "pump_fun" (default), "lets_bonk" @@ -50,6 +50,13 @@ priority_fees: extra_percentage: 0.0 # Percentage increase on riority fee regardless of the calculation method (0.1 = 10%) hard_cap: 200_000 # Maximum allowable fee in microlamports to prevent excessive spending +# Compute unit limits for transaction processing +# Operation-specific defaults are used if not specified: buy=100K, sell=60K +compute_units: + # Override default CU limits for this platform + # buy: 100_000 # Buy operations (ATA creation + trading) + # sell: 60_000 # Sell operations (just trading) + # Filters for token selection filters: match_string: null # Only process tokens with this string in name/symbol diff --git a/bots/bot-sniper-3-blocks.yaml b/bots/bot-sniper-3-blocks.yaml index f2acd0f..7e8d2b7 100644 --- a/bots/bot-sniper-3-blocks.yaml +++ b/bots/bot-sniper-3-blocks.yaml @@ -8,11 +8,11 @@ rpc_endpoint: "${SOLANA_NODE_RPC_ENDPOINT}" wss_endpoint: "${SOLANA_NODE_WSS_ENDPOINT}" private_key: "${SOLANA_PRIVATE_KEY}" -enabled: false # You can turn off the bot w/o removing its config +enabled: true # You can turn off the bot w/o removing its config separate_process: true # Options: "pump_fun" (default), "lets_bonk" -platform: "lets_bonk" +platform: "pump_fun" # Geyser configuration (fastest method for getting updates) geyser: @@ -50,6 +50,13 @@ priority_fees: extra_percentage: 0.0 # Percentage increase on riority fee regardless of the calculation method (0.1 = 10%) hard_cap: 200_000 # Maximum allowable fee in microlamports to prevent excessive spending +# Compute unit limits for transaction processing +# Operation-specific defaults are used if not specified: buy=100K, sell=60K +compute_units: + # Override default CU limits for this platform + # buy: 100_000 # Buy operations (ATA creation + trading) + # sell: 60_000 # Sell operations (just trading) + # Filters for token selection filters: match_string: null # Only process tokens with this string in name/symbol diff --git a/bots/bot-sniper-4-pp.yaml b/bots/bot-sniper-4-pp.yaml index 4646d35..c9116e2 100644 --- a/bots/bot-sniper-4-pp.yaml +++ b/bots/bot-sniper-4-pp.yaml @@ -48,6 +48,13 @@ priority_fees: extra_percentage: 0.0 # Percentage increase on riority fee regardless of the calculation method (0.1 = 10%) hard_cap: 200_000 # Maximum allowable fee in microlamports to prevent excessive spending +# Compute unit limits for transaction processing +# Operation-specific defaults are used if not specified: buy=100K, sell=60K +compute_units: + # Override default CU limits for this platform + # buy: 100_000 # Buy operations (ATA creation + trading) + # sell: 60_000 # Sell operations (just trading) + # Filters for token selection filters: match_string: null # Only process tokens with this string in name/symbol diff --git a/learning-examples/pumpswap/manual_sell_pumpswap.py b/learning-examples/pumpswap/manual_sell_pumpswap.py index 756a10d..b74b406 100644 --- a/learning-examples/pumpswap/manual_sell_pumpswap.py +++ b/learning-examples/pumpswap/manual_sell_pumpswap.py @@ -174,7 +174,7 @@ def find_coin_creator_vault(coin_creator: Pubkey) -> Pubkey: def find_fee_config() -> Pubkey: """Derive the Program Derived Address (PDA) for the fee config. - + Returns: Pubkey of the derived fee config account """ diff --git a/src/bot_runner.py b/src/bot_runner.py index e5b130a..4a47e52 100644 --- a/src/bot_runner.py +++ b/src/bot_runner.py @@ -135,6 +135,8 @@ async def start_bot(config_path: str): bro_address=cfg["filters"].get("bro_address"), marry_mode=cfg["filters"].get("marry_mode", False), yolo_mode=cfg["filters"].get("yolo_mode", False), + # Compute unit configuration + compute_units=cfg.get("compute_units", {}), ) await trader.start() diff --git a/src/core/client.py b/src/core/client.py index 08febce..c9ce30a 100644 --- a/src/core/client.py +++ b/src/core/client.py @@ -145,15 +145,18 @@ class SolanaClient: skip_preflight: bool = True, max_retries: int = 3, priority_fee: int | None = None, + compute_unit_limit: int | None = None, ) -> str: """ - Send a transaction with optional priority fee. + Send a transaction with optional priority fee and compute unit limit. Args: instructions: List of instructions to include in the transaction. + signer_keypair: Keypair to sign the transaction. skip_preflight: Whether to skip preflight checks. max_retries: Maximum number of retry attempts. priority_fee: Optional priority fee in microlamports. + compute_unit_limit: Optional compute unit limit. Defaults to 85,000 if not provided. Returns: Transaction signature. @@ -164,12 +167,18 @@ class SolanaClient: f"Priority fee in microlamports: {priority_fee if priority_fee else 0}" ) - # Add priority fee instructions if applicable - if priority_fee is not None: - fee_instructions = [ - set_compute_unit_limit(85_000), # Default compute unit limit - set_compute_unit_price(priority_fee), - ] + # Add compute budget instructions if applicable + if priority_fee is not None or compute_unit_limit is not None: + fee_instructions = [] + + # Set compute unit limit (use provided value or default to 85,000) + cu_limit = compute_unit_limit if compute_unit_limit is not None else 85_000 + fee_instructions.append(set_compute_unit_limit(cu_limit)) + + # Set priority fee if provided + if priority_fee is not None: + fee_instructions.append(set_compute_unit_price(priority_fee)) + instructions = fee_instructions + instructions recent_blockhash = await self.get_cached_blockhash() diff --git a/src/interfaces/core.py b/src/interfaces/core.py index d0f9dea..65513e2 100644 --- a/src/interfaces/core.py +++ b/src/interfaces/core.py @@ -201,6 +201,30 @@ class InstructionBuilder(ABC): """ pass + @abstractmethod + def get_buy_compute_unit_limit(self, config_override: int | None = None) -> int: + """Get the recommended compute unit limit for buy operations. + + Args: + config_override: Optional override from configuration + + Returns: + Compute unit limit appropriate for buy operations + """ + pass + + @abstractmethod + def get_sell_compute_unit_limit(self, config_override: int | None = None) -> int: + """Get the recommended compute unit limit for sell operations. + + Args: + config_override: Optional override from configuration + + Returns: + Compute unit limit appropriate for sell operations + """ + pass + class CurveManager(ABC): """Abstract interface for platform-specific price calculations and pool state management.""" diff --git a/src/platforms/letsbonk/instruction_builder.py b/src/platforms/letsbonk/instruction_builder.py index 2ef3110..0117962 100644 --- a/src/platforms/letsbonk/instruction_builder.py +++ b/src/platforms/letsbonk/instruction_builder.py @@ -460,3 +460,31 @@ class LetsBonkInstructionBuilder(InstructionBuilder): Token amount in decimal form """ return token_amount_raw / 10**TOKEN_DECIMALS + + def get_buy_compute_unit_limit(self, config_override: int | None = None) -> int: + """Get the recommended compute unit limit for LetsBonk buy operations. + + Args: + config_override: Optional override from configuration + + Returns: + Compute unit limit appropriate for buy operations + """ + if config_override is not None: + return config_override + # Buy operations: ATA creation + WSOL creation/init/close + buy instruction + return 100_000 + + def get_sell_compute_unit_limit(self, config_override: int | None = None) -> int: + """Get the recommended compute unit limit for LetsBonk sell operations. + + Args: + config_override: Optional override from configuration + + Returns: + Compute unit limit appropriate for sell operations + """ + if config_override is not None: + return config_override + # Sell operations: WSOL creation/init/close + sell instruction + return 60_000 diff --git a/src/platforms/pumpfun/instruction_builder.py b/src/platforms/pumpfun/instruction_builder.py index 7aa24af..1237b0f 100644 --- a/src/platforms/pumpfun/instruction_builder.py +++ b/src/platforms/pumpfun/instruction_builder.py @@ -336,3 +336,31 @@ class PumpFunInstructionBuilder(InstructionBuilder): Token amount in decimal form """ return token_amount_raw / 10**TOKEN_DECIMALS + + def get_buy_compute_unit_limit(self, config_override: int | None = None) -> int: + """Get the recommended compute unit limit for pump.fun buy operations. + + Args: + config_override: Optional override from configuration + + Returns: + Compute unit limit appropriate for buy operations + """ + if config_override is not None: + return config_override + # Buy operations: ATA creation + buy instruction + return 100_000 + + def get_sell_compute_unit_limit(self, config_override: int | None = None) -> int: + """Get the recommended compute unit limit for pump.fun sell operations. + + Args: + config_override: Optional override from configuration + + Returns: + Compute unit limit appropriate for sell operations + """ + if config_override is not None: + return config_override + # Sell operations: typically just sell instruction (ATA exists) + return 60_000 diff --git a/src/trading/platform_aware.py b/src/trading/platform_aware.py index 589ffca..8e16f8a 100644 --- a/src/trading/platform_aware.py +++ b/src/trading/platform_aware.py @@ -30,6 +30,7 @@ class PlatformAwareBuyer(Trader): max_retries: int = 5, extreme_fast_token_amount: int = 0, extreme_fast_mode: bool = False, + compute_units: dict | None = None, ): """Initialize platform-aware token buyer.""" self.client = client @@ -40,6 +41,7 @@ class PlatformAwareBuyer(Trader): self.max_retries = max_retries self.extreme_fast_mode = extreme_fast_mode self.extreme_fast_token_amount = extreme_fast_token_amount + self.compute_units = compute_units or {} async def execute(self, token_info: TokenInfo) -> TradeResult: """Execute buy operation using platform-specific implementations.""" @@ -106,6 +108,9 @@ class PlatformAwareBuyer(Trader): priority_fee=await self.priority_fee_manager.calculate_priority_fee( priority_accounts ), + compute_unit_limit=instruction_builder.get_buy_compute_unit_limit( + self._get_cu_override("buy", token_info.platform) + ), ) success = await self.client.confirm_transaction(tx_signature) @@ -147,6 +152,22 @@ class PlatformAwareBuyer(Trader): # Fallback to deriving the address using platform provider return address_provider.derive_pool_address(token_info.mint) + def _get_cu_override(self, operation: str, platform: Platform) -> int | None: + """Get compute unit override from configuration. + + Args: + operation: "buy" or "sell" + platform: Trading platform (unused - each config is platform-specific) + + Returns: + CU override value if configured, None otherwise + """ + if not self.compute_units: + return None + + # Just check for operation override (buy/sell) + return self.compute_units.get(operation) + class PlatformAwareSeller(Trader): """Platform-aware token seller that works with any supported platform.""" @@ -158,6 +179,7 @@ class PlatformAwareSeller(Trader): priority_fee_manager: PriorityFeeManager, slippage: float = 0.25, max_retries: int = 5, + compute_units: dict | None = None, ): """Initialize platform-aware token seller.""" self.client = client @@ -165,6 +187,7 @@ class PlatformAwareSeller(Trader): self.priority_fee_manager = priority_fee_manager self.slippage = slippage self.max_retries = max_retries + self.compute_units = compute_units or {} async def execute(self, token_info: TokenInfo) -> TradeResult: """Execute sell operation using platform-specific implementations.""" @@ -203,18 +226,18 @@ class PlatformAwareSeller(Trader): logger.info(f"Price per Token: {token_price_sol:.8f} SOL") - # Calculate minimum SOL output with slippage - expected_sol_output = float(token_balance_decimal) * float(token_price_sol) + # Calculate expected SOL output + expected_sol_output = token_balance_decimal * token_price_sol + + # Calculate minimum SOL output with slippage protection min_sol_output = int( (expected_sol_output * (1 - self.slippage)) * LAMPORTS_PER_SOL ) - logger.info( - f"Selling {token_balance_decimal} tokens on {token_info.platform.value}" - ) + logger.info(f"Selling {token_balance_decimal} tokens on {token_info.platform.value}") logger.info(f"Expected SOL output: {expected_sol_output:.8f} SOL") logger.info( - f"Minimum SOL output (with {self.slippage * 100}% slippage): {min_sol_output / LAMPORTS_PER_SOL:.8f} SOL" + f"Minimum SOL output (with {self.slippage * 100:.1f}% slippage): {min_sol_output / LAMPORTS_PER_SOL:.8f} SOL" ) # Build sell instructions using platform-specific builder @@ -240,6 +263,9 @@ class PlatformAwareSeller(Trader): priority_fee=await self.priority_fee_manager.calculate_priority_fee( priority_accounts ), + compute_unit_limit=instruction_builder.get_sell_compute_unit_limit( + self._get_cu_override("sell", token_info.platform) + ), ) success = await self.client.confirm_transaction(tx_signature) @@ -280,3 +306,19 @@ class PlatformAwareSeller(Trader): # Fallback to deriving the address using platform provider return address_provider.derive_pool_address(token_info.mint) + + def _get_cu_override(self, operation: str, platform: Platform) -> int | None: + """Get compute unit override from configuration. + + Args: + operation: "buy" or "sell" + platform: Trading platform (unused - each config is platform-specific) + + Returns: + CU override value if configured, None otherwise + """ + if not self.compute_units: + return None + + # Just check for operation override (buy/sell) + return self.compute_units.get(operation) \ No newline at end of file diff --git a/src/trading/universal_trader.py b/src/trading/universal_trader.py index 1b9a1f9..c2a3a80 100644 --- a/src/trading/universal_trader.py +++ b/src/trading/universal_trader.py @@ -83,6 +83,8 @@ class UniversalTrader: bro_address: str | None = None, marry_mode: bool = False, yolo_mode: bool = False, + # Compute unit configuration + compute_units: dict | None = None, ): """Initialize the universal trader.""" # Core components @@ -120,6 +122,9 @@ class UniversalTrader: self.platform, self.solana_client ) + # Store compute unit configuration + self.compute_units = compute_units or {} + # Create platform-aware traders self.buyer = PlatformAwareBuyer( self.solana_client, @@ -130,6 +135,7 @@ class UniversalTrader: max_retries, extreme_fast_token_amount, extreme_fast_mode, + compute_units=self.compute_units, ) self.seller = PlatformAwareSeller( @@ -138,6 +144,7 @@ class UniversalTrader: self.priority_fee_manager, sell_slippage, max_retries, + compute_units=self.compute_units, ) # Initialize the appropriate listener with platform filtering