diff --git a/bots/bot-sniper-1-geyser.yaml b/bots/bot-sniper-1-geyser.yaml index 1346d8c..a836125 100644 --- a/bots/bot-sniper-1-geyser.yaml +++ b/bots/bot-sniper-1-geyser.yaml @@ -57,6 +57,13 @@ compute_units: # buy: 100_000 # Buy operations (ATA creation + trading) # sell: 60_000 # Sell operations (just trading) + # Account data size optimization (reduces CU cost and improves tx priority) + # Reduces CU cost from 16k to ~128 CU by limiting loaded account data. + # Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead. + # Note: Savings don't show in "consumed CU" but improve tx priority/cost. + # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit + account_data_size: 512_000 # 512KB limit + # 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 0283b25..9564921 100644 --- a/bots/bot-sniper-2-logs.yaml +++ b/bots/bot-sniper-2-logs.yaml @@ -57,6 +57,13 @@ compute_units: # buy: 100_000 # Buy operations (ATA creation + trading) # sell: 60_000 # Sell operations (just trading) + # Account data size optimization (reduces CU cost and improves tx priority) + # Reduces CU cost from 16k to ~128 CU by limiting loaded account data. + # Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead. + # Note: Savings don't show in "consumed CU" but improve tx priority/cost. + # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit + account_data_size: 512_000 # 512KB limit + # 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 7e8d2b7..2eae5f4 100644 --- a/bots/bot-sniper-3-blocks.yaml +++ b/bots/bot-sniper-3-blocks.yaml @@ -57,6 +57,13 @@ compute_units: # buy: 100_000 # Buy operations (ATA creation + trading) # sell: 60_000 # Sell operations (just trading) + # Account data size optimization (reduces CU cost and improves tx priority) + # Reduces CU cost from 16k to ~128 CU by limiting loaded account data. + # Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead. + # Note: Savings don't show in "consumed CU" but improve tx priority/cost. + # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit + account_data_size: 512_000 # 512KB limit + # 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 c9116e2..f27257d 100644 --- a/bots/bot-sniper-4-pp.yaml +++ b/bots/bot-sniper-4-pp.yaml @@ -55,6 +55,13 @@ compute_units: # buy: 100_000 # Buy operations (ATA creation + trading) # sell: 60_000 # Sell operations (just trading) + # Account data size optimization (reduces CU cost and improves tx priority) + # Reduces CU cost from 16k to ~128 CU by limiting loaded account data. + # Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead. + # Note: Savings don't show in "consumed CU" but improve tx priority/cost. + # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit + account_data_size: 512_000 # 512KB limit + # Filters for token selection filters: match_string: null # Only process tokens with this string in name/symbol diff --git a/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py b/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py index 9e823c2..b7327a4 100644 --- a/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py +++ b/learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py @@ -16,7 +16,9 @@ # Constants RPC_URL: Final[str] = os.getenv("SOLANA_NODE_RPC_ENDPOINT") -TOKEN_MINT: Final[str] = "YOUR_TOKEN_MINT_ADDRESS_HERE" # Replace with actual token mint address +TOKEN_MINT: Final[str] = ( + "YOUR_TOKEN_MINT_ADDRESS_HERE" # Replace with actual token mint address +) PUMP_PROGRAM_ID: Final[Pubkey] = Pubkey.from_string( "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" ) diff --git a/learning-examples/fetch_price.py b/learning-examples/fetch_price.py index cf89cf0..df916e8 100644 --- a/learning-examples/fetch_price.py +++ b/learning-examples/fetch_price.py @@ -12,7 +12,9 @@ LAMPORTS_PER_SOL: Final[int] = 1_000_000_000 TOKEN_DECIMALS: Final[int] = 6 -CURVE_ADDRESS: Final[str] = "YOUR_BONDING_CURVE_ADDRESS_HERE" # Replace with actual bonding curve address +CURVE_ADDRESS: Final[str] = ( + "YOUR_BONDING_CURVE_ADDRESS_HERE" # Replace with actual bonding curve address +) # Here and later all the discriminators are precalculated. See learning-examples/calculate_discriminator.py EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack(" Instruction: + """ + Create SetLoadedAccountsDataSizeLimit instruction to reduce CU consumption. + + By default, Solana transactions can load up to 64MB of account data, + costing 16k CU (8 CU per 32KB). Setting a lower limit reduces CU + consumption and improves transaction priority. + + NOTE: CU savings are NOT visible in "consumed CU" metrics, which only + show execution CU. The 16k CU loaded accounts overhead is counted + separately for transaction priority/cost calculation. + + Args: + bytes_limit: Max account data size in bytes (e.g., 512_000 = 512KB) + + Returns: + Compute Budget instruction with discriminator 4 + + Reference: + https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit + """ + COMPUTE_BUDGET_PROGRAM = Pubkey.from_string( + "ComputeBudget111111111111111111111111111111" + ) + + data = struct.pack(" str: """ Send a transaction with optional priority fee and compute unit limit. @@ -157,6 +188,8 @@ async def build_and_send_transaction( 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. + account_data_size_limit: Optional account data size limit in bytes (e.g., 512_000). + Reduces CU cost from 16k to ~128 CU. Must be first instruction. Returns: Transaction signature. @@ -168,9 +201,19 @@ async def build_and_send_transaction( ) # Add compute budget instructions if applicable - if priority_fee is not None or compute_unit_limit is not None: + if ( + priority_fee is not None + or compute_unit_limit is not None + or account_data_size_limit is not None + ): fee_instructions = [] + if account_data_size_limit is not None: + fee_instructions.append( + set_loaded_accounts_data_size_limit(account_data_size_limit) + ) + logger.info(f"Account data size limit: {account_data_size_limit} bytes") + # 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)) diff --git a/src/platforms/letsbonk/curve_manager.py b/src/platforms/letsbonk/curve_manager.py index b6d3ad4..1c5eccd 100644 --- a/src/platforms/letsbonk/curve_manager.py +++ b/src/platforms/letsbonk/curve_manager.py @@ -186,7 +186,9 @@ def _decode_pool_state_with_idl(self, data: bytes) -> dict[str, Any]: "real_quote": decoded_pool_state.get("real_quote", 0), "status": decoded_pool_state.get("status", 0), "supply": decoded_pool_state.get("supply", 0), - "creator": decoded_pool_state.get("creator"), # Creator pubkey (as base58 string) + "creator": decoded_pool_state.get( + "creator" + ), # Creator pubkey (as base58 string) "base_vault": decoded_pool_state.get("base_vault"), # Base vault pubkey "quote_vault": decoded_pool_state.get("quote_vault"), # Quote vault pubkey } diff --git a/src/platforms/letsbonk/event_parser.py b/src/platforms/letsbonk/event_parser.py index 566be79..035b391 100644 --- a/src/platforms/letsbonk/event_parser.py +++ b/src/platforms/letsbonk/event_parser.py @@ -143,7 +143,17 @@ def get_account_key(index): base_vault = get_account_key(8) # base_vault account quote_vault = get_account_key(9) # quote_vault account - if not all([creator, global_config, platform_config, pool_state, base_mint, base_vault, quote_vault]): + if not all( + [ + creator, + global_config, + platform_config, + pool_state, + base_mint, + base_vault, + quote_vault, + ] + ): logger.debug( f"Missing required accounts: creator={creator}, global_config={global_config}, " f"platform_config={platform_config}, pool_state={pool_state}, base_mint={base_mint}, " diff --git a/src/trading/platform_aware.py b/src/trading/platform_aware.py index 8e16f8a..9aaca51 100644 --- a/src/trading/platform_aware.py +++ b/src/trading/platform_aware.py @@ -111,6 +111,9 @@ async def execute(self, token_info: TokenInfo) -> TradeResult: compute_unit_limit=instruction_builder.get_buy_compute_unit_limit( self._get_cu_override("buy", token_info.platform) ), + account_data_size_limit=self._get_cu_override( + "account_data_size", token_info.platform + ), ) success = await self.client.confirm_transaction(tx_signature) @@ -154,17 +157,17 @@ def _get_pool_address( 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) @@ -234,7 +237,9 @@ async def execute(self, token_info: TokenInfo) -> TradeResult: (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:.1f}% slippage): {min_sol_output / LAMPORTS_PER_SOL:.8f} SOL" @@ -266,6 +271,9 @@ async def execute(self, token_info: TokenInfo) -> TradeResult: compute_unit_limit=instruction_builder.get_sell_compute_unit_limit( self._get_cu_override("sell", token_info.platform) ), + account_data_size_limit=self._get_cu_override( + "account_data_size", token_info.platform + ), ) success = await self.client.confirm_transaction(tx_signature) @@ -309,16 +317,16 @@ def _get_pool_address( 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 + return self.compute_units.get(operation)