From 075e5ae191553137480801904c43982aa456cd15 Mon Sep 17 00:00:00 2001 From: smypmsa Date: Tue, 25 Mar 2025 16:25:12 +0000 Subject: [PATCH 1/6] chore: scaffold cleanup module and config for ATA closing feature --- src/cleanup/__init__.py | 0 src/cleanup/manager.py | 0 src/cleanup/modes.py | 0 src/config.py | 15 +++++++++++++++ 4 files changed, 15 insertions(+) create mode 100644 src/cleanup/__init__.py create mode 100644 src/cleanup/manager.py create mode 100644 src/cleanup/modes.py diff --git a/src/cleanup/__init__.py b/src/cleanup/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/cleanup/manager.py b/src/cleanup/manager.py new file mode 100644 index 0000000..e69de29 diff --git a/src/cleanup/modes.py b/src/cleanup/modes.py new file mode 100644 index 0000000..e69de29 diff --git a/src/config.py b/src/config.py index a2b8d15..21b26e5 100644 --- a/src/config.py +++ b/src/config.py @@ -48,6 +48,21 @@ WAIT_TIME_BEFORE_NEW_TOKEN: int | float = ( MAX_TOKEN_AGE: int | float = 0.1 +# Cleanup configuration + +# CLEANUP_MODE controls when to attempt closing token accounts (ATA) +# Options: +# - "disabled": no cleanup at all +# - "on_fail": close ATA only if a buy transaction fails +# - "after_sell": close ATA after selling, but only if token balance is zero +# - "post_session": clean up all empty ATA accounts at the end of trading session +CLEANUP_MODE: str = "disabled" + +# If True, cleanup transactions will skip priority fees (cheaper, slower confirmation) +# Set to False if you want faster confirmations (e.g. when racing for SOL reclaim) +CLEANUP_WITHOUT_PRIORITY_FEE: bool = True + + # Node provider configuration # Tested with Chainstack nodes (https://console.chainstack.com), but you can use any node provider # You can get a trader node https://docs.chainstack.com/docs/solana-trader-nodes From 6d9d0a106d1fdcb0a8b3b5534161bfafd8f076b3 Mon Sep 17 00:00:00 2001 From: smypmsa Date: Thu, 27 Mar 2025 14:59:15 +0000 Subject: [PATCH 2/6] fix: minor formatting fixes in cli --- src/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli.py b/src/cli.py index 983f880..90a4620 100644 --- a/src/cli.py +++ b/src/cli.py @@ -8,7 +8,7 @@ import asyncio import os import sys -import config as config +import config from trading.trader import PumpTrader from utils.logger import get_logger, setup_file_logging @@ -109,7 +109,7 @@ async def main() -> None: except KeyboardInterrupt: logger.info("Trading stopped by user") except Exception as e: - logger.error(f"Trading stopped due to error: {str(e)}") + logger.error(f"Trading stopped due to error: {e!s}") finally: try: await trader.solana_client.close() @@ -117,7 +117,7 @@ async def main() -> None: pass -def sync_main(): +def sync_main() -> None: asyncio.run(main()) From 735ab11d4d711d9dd7a2063e75ec772399d37696 Mon Sep 17 00:00:00 2001 From: smypmsa Date: Thu, 27 Mar 2025 15:19:52 +0000 Subject: [PATCH 3/6] feat: added cleanup manager and modes --- src/cleanup/manager.py | 83 ++++++++++++++++++++++++++++++++++++++++++ src/cleanup/modes.py | 39 ++++++++++++++++++++ src/trading/trader.py | 8 ++-- 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/cleanup/manager.py b/src/cleanup/manager.py index e69de29..eb00e53 100644 --- a/src/cleanup/manager.py +++ b/src/cleanup/manager.py @@ -0,0 +1,83 @@ +from solders.pubkey import Pubkey +from spl.token.instructions import BurnParams, CloseAccountParams, burn, close_account + +from config import CLEANUP_WITHOUT_PRIORITY_FEE +from core.client import SolanaClient +from core.pubkeys import SystemAddresses +from core.wallet import Wallet +from utils.logger import get_logger + +logger = get_logger(__name__) + + +class AccountCleanupManager: + """Handles safe cleanup of token accounts (ATA) after trading sessions.""" + + def __init__( + self, + client: SolanaClient, + wallet: Wallet, + ): + """ + Args: + client: Solana RPC client + wallet: Wallet for signing transactions + """ + self.client = client + self.wallet = wallet + self.use_priority_fee = not CLEANUP_WITHOUT_PRIORITY_FEE + + async def cleanup_ata(self, mint: Pubkey) -> None: + """ + Attempt to burn any remaining tokens and close the ATA. + Skips if account doesn't exist or is already empty/closed. + """ + ata = self.wallet.get_associated_token_address(mint) + solana_client = await self.client.get_client() + + try: + info = await solana_client.get_account_info(ata) + if not info.value: + logger.info(f"ATA {ata} does not exist or already closed.") + return + + balance = await self.client.get_token_account_balance(ata) + if balance > 0: + logger.info(f"⚠️ Burning {balance} tokens from ATA {ata} (mint: {mint})...") + burn_ix = burn( + BurnParams( + account=ata, + mint=mint, + owner=self.wallet.pubkey, + amount=balance, + program_id=SystemAddresses.TOKEN_PROGRAM, + ) + ) + await self.client.build_and_send_transaction( + [burn_ix], + self.wallet.keypair, + skip_preflight=True, + priority_fee=None if not self.use_priority_fee else 0, + ) + logger.info(f"✅ Burned successfully from ATA {ata}") + + logger.info(f"Closing ATA: {ata}") + close_ix = close_account( + CloseAccountParams( + account=ata, + dest=self.wallet.pubkey, + owner=self.wallet.pubkey, + program_id=SystemAddresses.TOKEN_PROGRAM, + ) + ) + tx_sig = await self.client.build_and_send_transaction( + [close_ix], + self.wallet.keypair, + skip_preflight=True, + priority_fee=None if not self.use_priority_fee else 0, + ) + await self.client.confirm_transaction(tx_sig) + logger.info(f"✅ Closed successfully: {ata}") + + except Exception as e: + logger.warning(f"⚠️ Cleanup failed for ATA {ata}: {e!s}") diff --git a/src/cleanup/modes.py b/src/cleanup/modes.py index e69de29..26cf079 100644 --- a/src/cleanup/modes.py +++ b/src/cleanup/modes.py @@ -0,0 +1,39 @@ +from cleanup.manager import AccountCleanupManager +from config import CLEANUP_MODE, CLEANUP_WITHOUT_PRIORITY_FEE +from utils.logger import get_logger + +logger = get_logger(__name__) + + +def should_cleanup_after_failure() -> bool: + return CLEANUP_MODE == "on_fail" + + +def should_cleanup_after_sell() -> bool: + return CLEANUP_MODE == "after_sell" + + +def should_cleanup_post_session() -> bool: + return CLEANUP_MODE == "post_session" + + +async def handle_cleanup_after_failure(client, wallet, mint): + if should_cleanup_after_failure(): + logger.info("[Cleanup] Triggered by failed buy transaction.") + manager = AccountCleanupManager(client, wallet, use_priority_fee=not CLEANUP_WITHOUT_PRIORITY_FEE) + await manager.cleanup_ata(mint) + + +async def handle_cleanup_after_sell(client, wallet, mint): + if should_cleanup_after_sell(): + logger.info("[Cleanup] Triggered after token sell.") + manager = AccountCleanupManager(client, wallet, use_priority_fee=not CLEANUP_WITHOUT_PRIORITY_FEE) + await manager.cleanup_ata(mint) + + +async def handle_cleanup_post_session(client, wallet, mints): + if should_cleanup_post_session(): + logger.info("[Cleanup] Triggered post trading session.") + manager = AccountCleanupManager(client, wallet, use_priority_fee=not CLEANUP_WITHOUT_PRIORITY_FEE) + for mint in mints: + await manager.cleanup_ata(mint) diff --git a/src/trading/trader.py b/src/trading/trader.py index 6204217..470b125 100644 --- a/src/trading/trader.py +++ b/src/trading/trader.py @@ -8,7 +8,7 @@ import json import os from datetime import datetime -import config as config +import config from core.client import SolanaClient from core.curve import BondingCurveManager from core.priority_fee.manager import PriorityFeeManager @@ -137,7 +137,7 @@ class PumpTrader: ) except Exception as e: - logger.error(f"Trading stopped due to error: {str(e)}") + logger.error(f"Trading stopped due to error: {e!s}") processor_task.cancel() await self.solana_client.close() @@ -153,7 +153,7 @@ class PumpTrader: self.token_timestamps[token_key] = asyncio.get_event_loop().time() await self.token_queue.put(token_info) - # logger.info(f"Queued new token: {token_info.symbol} ({token_info.mint})") + logger.info(f"Queued new token: {token_info.symbol} ({token_info.mint})") async def _process_token_queue(self, marry_mode: bool, yolo_mode: bool) -> None: """Continuously process tokens from the queue, only if they're fresh.""" @@ -254,7 +254,7 @@ class PumpTrader: await asyncio.sleep(config.WAIT_TIME_BEFORE_NEW_TOKEN) except Exception as e: - logger.error(f"Error handling token {token_info.symbol}: {str(e)}") + logger.error(f"Error handling token {token_info.symbol}: {e!s}") async def _save_token_info(self, token_info: TokenInfo) -> None: """Save token information to a file. From 5c2d044569e1d6efba1086ac86f8c60731fcaa9c Mon Sep 17 00:00:00 2001 From: smypmsa Date: Thu, 27 Mar 2025 21:11:48 +0000 Subject: [PATCH 4/6] feat: cleanup manager integrated into trader, enhanced config --- src/cleanup/manager.py | 33 ++++++--- src/cleanup/modes.py | 16 ++--- src/config.py | 150 +++++++++++++++++++++++------------------ src/trading/trader.py | 21 ++++++ 4 files changed, 135 insertions(+), 85 deletions(-) diff --git a/src/cleanup/manager.py b/src/cleanup/manager.py index eb00e53..286e009 100644 --- a/src/cleanup/manager.py +++ b/src/cleanup/manager.py @@ -1,8 +1,9 @@ from solders.pubkey import Pubkey from spl.token.instructions import BurnParams, CloseAccountParams, burn, close_account -from config import CLEANUP_WITHOUT_PRIORITY_FEE +from config import CLEANUP_FORCE_CLOSE_WITH_BURN from core.client import SolanaClient +from core.priority_fee.manager import PriorityFeeManager from core.pubkeys import SystemAddresses from core.wallet import Wallet from utils.logger import get_logger @@ -12,11 +13,12 @@ logger = get_logger(__name__) class AccountCleanupManager: """Handles safe cleanup of token accounts (ATA) after trading sessions.""" - def __init__( self, client: SolanaClient, wallet: Wallet, + priority_fee_manager: PriorityFeeManager, + use_priority_fee: bool = False, ): """ Args: @@ -25,7 +27,8 @@ class AccountCleanupManager: """ self.client = client self.wallet = wallet - self.use_priority_fee = not CLEANUP_WITHOUT_PRIORITY_FEE + self.priority_fee_manager = priority_fee_manager + self.use_priority_fee = use_priority_fee async def cleanup_ata(self, mint: Pubkey) -> None: """ @@ -35,6 +38,12 @@ class AccountCleanupManager: ata = self.wallet.get_associated_token_address(mint) solana_client = await self.client.get_client() + priority_fee = ( + await self.priority_fee_manager.calculate_priority_fee([ata]) + if self.use_priority_fee + else None + ) + try: info = await solana_client.get_account_info(ata) if not info.value: @@ -42,8 +51,8 @@ class AccountCleanupManager: return balance = await self.client.get_token_account_balance(ata) - if balance > 0: - logger.info(f"⚠️ Burning {balance} tokens from ATA {ata} (mint: {mint})...") + if balance > 0 and CLEANUP_FORCE_CLOSE_WITH_BURN: + logger.info(f"Burning {balance} tokens from ATA {ata} (mint: {mint})...") burn_ix = burn( BurnParams( account=ata, @@ -57,9 +66,15 @@ class AccountCleanupManager: [burn_ix], self.wallet.keypair, skip_preflight=True, - priority_fee=None if not self.use_priority_fee else 0, + priority_fee=priority_fee, ) logger.info(f"✅ Burned successfully from ATA {ata}") + elif balance > 0: + logger.info( + f"Skipping ATA {ata} with non-zero balance ({balance} tokens) " + f"because CLEANUP_FORCE_CLOSE_WITH_BURN is disabled." + ) + return logger.info(f"Closing ATA: {ata}") close_ix = close_account( @@ -74,10 +89,10 @@ class AccountCleanupManager: [close_ix], self.wallet.keypair, skip_preflight=True, - priority_fee=None if not self.use_priority_fee else 0, + priority_fee=priority_fee, ) await self.client.confirm_transaction(tx_sig) - logger.info(f"✅ Closed successfully: {ata}") + logger.info(f"Closed successfully: {ata}") except Exception as e: - logger.warning(f"⚠️ Cleanup failed for ATA {ata}: {e!s}") + logger.warning(f"Cleanup failed for ATA {ata}: {e!s}") diff --git a/src/cleanup/modes.py b/src/cleanup/modes.py index 26cf079..8c11794 100644 --- a/src/cleanup/modes.py +++ b/src/cleanup/modes.py @@ -1,5 +1,5 @@ from cleanup.manager import AccountCleanupManager -from config import CLEANUP_MODE, CLEANUP_WITHOUT_PRIORITY_FEE +from config import CLEANUP_MODE, CLEANUP_WITH_PRIORITY_FEE from utils.logger import get_logger logger = get_logger(__name__) @@ -17,23 +17,21 @@ def should_cleanup_post_session() -> bool: return CLEANUP_MODE == "post_session" -async def handle_cleanup_after_failure(client, wallet, mint): +async def handle_cleanup_after_failure(client, wallet, mint, priority_fee_manager): if should_cleanup_after_failure(): logger.info("[Cleanup] Triggered by failed buy transaction.") - manager = AccountCleanupManager(client, wallet, use_priority_fee=not CLEANUP_WITHOUT_PRIORITY_FEE) + manager = AccountCleanupManager(client, wallet, priority_fee_manager, CLEANUP_WITH_PRIORITY_FEE) await manager.cleanup_ata(mint) - -async def handle_cleanup_after_sell(client, wallet, mint): +async def handle_cleanup_after_sell(client, wallet, mint, priority_fee_manager): if should_cleanup_after_sell(): logger.info("[Cleanup] Triggered after token sell.") - manager = AccountCleanupManager(client, wallet, use_priority_fee=not CLEANUP_WITHOUT_PRIORITY_FEE) + manager = AccountCleanupManager(client, wallet, priority_fee_manager, CLEANUP_WITH_PRIORITY_FEE) await manager.cleanup_ata(mint) - -async def handle_cleanup_post_session(client, wallet, mints): +async def handle_cleanup_post_session(client, wallet, mints, priority_fee_manager): if should_cleanup_post_session(): logger.info("[Cleanup] Triggered post trading session.") - manager = AccountCleanupManager(client, wallet, use_priority_fee=not CLEANUP_WITHOUT_PRIORITY_FEE) + manager = AccountCleanupManager(client, wallet, priority_fee_manager, CLEANUP_WITH_PRIORITY_FEE) for mint in mints: await manager.cleanup_ata(mint) diff --git a/src/config.py b/src/config.py index 21b26e5..0a87f04 100644 --- a/src/config.py +++ b/src/config.py @@ -1,87 +1,103 @@ """ Configuration for the pump.fun trading bot. + +This file defines comprehensive parameters and settings for the trading bot. +Carefully review and adjust values to match your trading strategy and risk tolerance. """ # Trading parameters -BUY_AMOUNT: int | float = 0.000_001 # Amount of SOL to spend when buying -BUY_SLIPPAGE: float = 0.4 # 40% slippage tolerance for buying -SELL_SLIPPAGE: float = 0.4 # 40% slippage tolerance for selling +# Control trade execution: amount of SOL per trade and acceptable price deviation +BUY_AMOUNT: int | float = 0.000_001 # Minimal SOL amount to prevent dust transactions +BUY_SLIPPAGE: float = 0.4 # Maximum acceptable price deviation (0.4 = 40%) +SELL_SLIPPAGE: float = 0.4 # Consistent slippage tolerance to maintain trading strategy -# Configuration for priority fee settings -ENABLE_DYNAMIC_PRIORITY_FEE: bool = False # Enable dynamic priority fee calculation -ENABLE_FIXED_PRIORITY_FEE: bool = True # Enable fixed priority fee -FIXED_PRIORITY_FEE: int = 2_000 # Fixed priority fee in microlamports -EXTRA_PRIORITY_FEE: float = ( - 0.0 # Percentage increase applied to priority fee (0.1 = 10%) -) -HARD_CAP_PRIOR_FEE: int = ( - 200_000 # Maximum allowed priority fee in microlamports (hard cap) -) +# Priority fee configuration +# Manage transaction speed and cost on the Solana network +ENABLE_DYNAMIC_PRIORITY_FEE: bool = False # Adaptive fee calculation +ENABLE_FIXED_PRIORITY_FEE: bool = True # Use consistent, predictable fee +FIXED_PRIORITY_FEE: int = 2_000 # Base fee in microlamports +EXTRA_PRIORITY_FEE: float = 0.0 # Percentage increase on base priority fee (0.1 = 10%) +HARD_CAP_PRIOR_FEE: int = 200_000 # Maximum allowable fee to prevent excessive spending in microlamports # Listener configuration -LISTENER_TYPE = "block" # Options: "block" or "logs" +# Choose method for detecting new tokens on the network +# "logs": Recommended for more stable token detection +# "blocks": Unstable method, potentially less reliable +LISTENER_TYPE = "logs" -# Retries and timeouts -MAX_RETRIES: int = 10 # Number of retries for transaction sending -# TODO: waiting times will be replaced with retries to shorten delays -WAIT_TIME_AFTER_CREATION: int | float = ( - 15 # Time to wait after token creation (in seconds) - # Too short a delay may cause the RPC node to be unaware of the bonding curve account -) -WAIT_TIME_AFTER_BUY: int | float = ( - 15 # Time to wait after a buy transaction is confirmed (in seconds) - # Acts as a simple holding period - # Too short delay may cause the RPC node to be unaware of account balance -) -WAIT_TIME_BEFORE_NEW_TOKEN: int | float = ( - 5 # Time to wait after a sell transaction is confirmed (in seconds) - # Provides a pause between completed trades, can be set to 0 -) +# Retry and timeout settings +# Control bot resilience and transaction handling +MAX_RETRIES: int = 10 # Number of attempts for transaction submission + +# Waiting periods in seconds between actions (TODO: to be replaced with retry mechanism) +WAIT_TIME_AFTER_CREATION: int | float = 15 # Seconds to wait after token creation +WAIT_TIME_AFTER_BUY: int | float = 15 # Holding period after buy transaction +WAIT_TIME_BEFORE_NEW_TOKEN: int | float = 15 # Pause between token trades -# Maximum age (in seconds) for a token to be considered "fresh" and eligible for processing. -# This threshold is checked before processing starts - tokens older than this are skipped -# since they likely contain outdated information from the websocket stream -MAX_TOKEN_AGE: int | float = 0.1 +# Token and account management +# Control token processing and account cleanup strategies +MAX_TOKEN_AGE: int | float = 0.1 # Maximum token age in seconds for processing + +# Cleanup mode determines when to manage token accounts. Options: +# "disabled": No cleanup will occur. +# "on_fail": Only clean up if a buy transaction fails. +# "after_sell": Clean up after selling, but only if the balance is zero. +# "post_session": Clean up all empty accounts after a trading session ends. +CLEANUP_MODE: str = "after_sell" +CLEANUP_FORCE_CLOSE_WITH_BURN: bool = True # Burn remaining tokens before closing account, else skip ATA with non-zero balances +CLEANUP_WITH_PRIORITY_FEE: bool = False # Use priority fees for cleanup transactions -# Cleanup configuration - -# CLEANUP_MODE controls when to attempt closing token accounts (ATA) -# Options: -# - "disabled": no cleanup at all -# - "on_fail": close ATA only if a buy transaction fails -# - "after_sell": close ATA after selling, but only if token balance is zero -# - "post_session": clean up all empty ATA accounts at the end of trading session -CLEANUP_MODE: str = "disabled" - -# If True, cleanup transactions will skip priority fees (cheaper, slower confirmation) -# Set to False if you want faster confirmations (e.g. when racing for SOL reclaim) -CLEANUP_WITHOUT_PRIORITY_FEE: bool = True +# Node provider configuration (TODO: to be implemented) +# Manage RPC node interaction to prevent rate limiting +MAX_RPS: int = 25 # Maximum requests per second -# Node provider configuration -# Tested with Chainstack nodes (https://console.chainstack.com), but you can use any node provider -# You can get a trader node https://docs.chainstack.com/docs/solana-trader-nodes -MAX_RPS: int = 25 # TODO: not implemented. Max RPS to avoid rate limit errors +def validate_configuration() -> None: + """ + Comprehensive validation of bot configuration. + + Checks: + - Type correctness + - Value ranges + - Logical consistency of settings + """ + # Configuration validation checks + config_checks = [ + # (value, type, min_value, max_value, error_message) + (BUY_AMOUNT, (int, float), 0, float('inf'), "BUY_AMOUNT must be a positive number"), + (BUY_SLIPPAGE, float, 0, 1, "BUY_SLIPPAGE must be between 0 and 1"), + (SELL_SLIPPAGE, float, 0, 1, "SELL_SLIPPAGE must be between 0 and 1"), + (FIXED_PRIORITY_FEE, int, 0, float('inf'), "FIXED_PRIORITY_FEE must be a non-negative integer"), + (EXTRA_PRIORITY_FEE, float, 0, 1, "EXTRA_PRIORITY_FEE must be between 0 and 1"), + (HARD_CAP_PRIOR_FEE, int, 0, float('inf'), "HARD_CAP_PRIOR_FEE must be a non-negative integer"), + (MAX_RETRIES, int, 0, 100, "MAX_RETRIES must be between 0 and 100") + ] + + for value, expected_type, min_val, max_val, error_msg in config_checks: + if not isinstance(value, expected_type): + raise ValueError(f"Type error: {error_msg}") + + if isinstance(value, (int, float)) and not (min_val <= value <= max_val): + raise ValueError(f"Range error: {error_msg}") + + # Logical consistency checks + if ENABLE_DYNAMIC_PRIORITY_FEE and ENABLE_FIXED_PRIORITY_FEE: + raise ValueError("Cannot enable both dynamic and fixed priority fees simultaneously") + + # Validate listener type + if LISTENER_TYPE not in ["logs", "blocks"]: + raise ValueError("LISTENER_TYPE must be either 'logs' or 'blocks'") + + # Validate cleanup mode + valid_cleanup_modes = ["disabled", "on_fail", "after_sell", "post_session"] + if CLEANUP_MODE not in valid_cleanup_modes: + raise ValueError(f"CLEANUP_MODE must be one of {valid_cleanup_modes}") -def validate_priority_fee_config() -> None: - """Validate priority fee configuration values.""" - if not isinstance(ENABLE_DYNAMIC_PRIORITY_FEE, bool): - raise ValueError("ENABLE_DYNAMIC_PRIORITY_FEE must be a boolean") - if not isinstance(ENABLE_FIXED_PRIORITY_FEE, bool): - raise ValueError("ENABLE_FIXED_PRIORITY_FEE must be a boolean") - if not isinstance(FIXED_PRIORITY_FEE, int) or FIXED_PRIORITY_FEE < 0: - raise ValueError("FIXED_PRIORITY_FEE must be a non-negative integer") - if not isinstance(EXTRA_PRIORITY_FEE, float) or EXTRA_PRIORITY_FEE < 0: - raise ValueError("EXTRA_PRIORITY_FEE must be a non-negative float") - if not isinstance(HARD_CAP_PRIOR_FEE, int) or HARD_CAP_PRIOR_FEE < 0: - raise ValueError("HARD_CAP_PRIOR_FEE must be a non-negative integer") - - -# Validate config on import -validate_priority_fee_config() +# Validate configuration on import +validate_configuration() \ No newline at end of file diff --git a/src/trading/trader.py b/src/trading/trader.py index 470b125..c5cf832 100644 --- a/src/trading/trader.py +++ b/src/trading/trader.py @@ -8,7 +8,14 @@ import json import os from datetime import datetime +from solders.pubkey import Pubkey + import config +from cleanup.modes import ( + handle_cleanup_after_failure, + handle_cleanup_after_sell, + handle_cleanup_post_session, +) from core.client import SolanaClient from core.curve import BondingCurveManager from core.priority_fee.manager import PriorityFeeManager @@ -96,6 +103,8 @@ class PumpTrader: self.max_retries = max_retries self.max_token_age = config.MAX_TOKEN_AGE + self.traded_mints: set[Pubkey] = set() + # Token processing state self.token_queue = asyncio.Queue() self.processing = False @@ -141,6 +150,13 @@ class PumpTrader: processor_task.cancel() await self.solana_client.close() + finally: + processor_task.cancel() + if self.traded_mints: + # Close ATA if enabled + await handle_cleanup_post_session(self.solana_client, self.wallet, list(self.traded_mints), self.priority_fee_manager) + await self.solana_client.close() + async def _queue_token(self, token_info: TokenInfo) -> None: """Queue a token for processing if not already processed.""" token_key = str(token_info.mint) @@ -215,10 +231,13 @@ class PumpTrader: buy_result.amount, # type: ignore buy_result.tx_signature, ) + self.traded_mints.add(token_info.mint) else: logger.error( f"Failed to buy {token_info.symbol}: {buy_result.error_message}" ) + # Close ATA if enabled + await handle_cleanup_after_failure(self.solana_client, self.wallet, token_info.mint, self.priority_fee_manager) # Sell token if not in marry mode if not marry_mode and buy_result.success: @@ -239,6 +258,8 @@ class PumpTrader: sell_result.amount, # type: ignore sell_result.tx_signature, ) + # Close ATA if enabled + await handle_cleanup_after_sell(self.solana_client, self.wallet, token_info.mint, self.priority_fee_manager) else: logger.error( f"Failed to sell {token_info.symbol}: {sell_result.error_message}" From 2514be2b317c054d6fedef25de4561a17d3a5bc7 Mon Sep 17 00:00:00 2001 From: smypmsa Date: Thu, 27 Mar 2025 21:13:12 +0000 Subject: [PATCH 5/6] chore: update default params --- src/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.py b/src/config.py index 0a87f04..9b978e6 100644 --- a/src/config.py +++ b/src/config.py @@ -47,8 +47,8 @@ MAX_TOKEN_AGE: int | float = 0.1 # Maximum token age in seconds for processing # "on_fail": Only clean up if a buy transaction fails. # "after_sell": Clean up after selling, but only if the balance is zero. # "post_session": Clean up all empty accounts after a trading session ends. -CLEANUP_MODE: str = "after_sell" -CLEANUP_FORCE_CLOSE_WITH_BURN: bool = True # Burn remaining tokens before closing account, else skip ATA with non-zero balances +CLEANUP_MODE: str = "disabled" +CLEANUP_FORCE_CLOSE_WITH_BURN: bool = False # Burn remaining tokens before closing account, else skip ATA with non-zero balances CLEANUP_WITH_PRIORITY_FEE: bool = False # Use priority fees for cleanup transactions From 7d64ff7245df9fc03a70d50cd1b212bc5b2f7a0e Mon Sep 17 00:00:00 2001 From: smypmsa Date: Thu, 27 Mar 2025 21:22:52 +0000 Subject: [PATCH 6/6] chore: fix typos in config --- src/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.py b/src/config.py index 9b978e6..e10a472 100644 --- a/src/config.py +++ b/src/config.py @@ -7,7 +7,7 @@ Carefully review and adjust values to match your trading strategy and risk toler # Trading parameters # Control trade execution: amount of SOL per trade and acceptable price deviation -BUY_AMOUNT: int | float = 0.000_001 # Minimal SOL amount to prevent dust transactions +BUY_AMOUNT: int | float = 0.000_001 # Amount of SOL to spend when buying BUY_SLIPPAGE: float = 0.4 # Maximum acceptable price deviation (0.4 = 40%) SELL_SLIPPAGE: float = 0.4 # Consistent slippage tolerance to maintain trading strategy @@ -17,7 +17,7 @@ SELL_SLIPPAGE: float = 0.4 # Consistent slippage tolerance to maintain trading ENABLE_DYNAMIC_PRIORITY_FEE: bool = False # Adaptive fee calculation ENABLE_FIXED_PRIORITY_FEE: bool = True # Use consistent, predictable fee FIXED_PRIORITY_FEE: int = 2_000 # Base fee in microlamports -EXTRA_PRIORITY_FEE: float = 0.0 # Percentage increase on base priority fee (0.1 = 10%) +EXTRA_PRIORITY_FEE: float = 0.0 # Percentage increase on priority fee (0.1 = 10%) HARD_CAP_PRIOR_FEE: int = 200_000 # Maximum allowable fee to prevent excessive spending in microlamports