feat(core): integrate account data size limit (#144)

* feat(core): integrate account data size limit in buyer and seller transaction

* refactor: format code for improved readability and consistency
This commit is contained in:
Anton Sauchyk
2025-10-28 21:21:21 +01:00
committed by GitHub
parent ec6d58665d
commit b6928d1f5f
10 changed files with 108 additions and 13 deletions
+7
View File
@@ -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
+7
View File
@@ -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
+7
View File
@@ -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
+7
View File
@@ -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
@@ -16,7 +16,9 @@ load_dotenv()
# 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"
)
+3 -1
View File
@@ -12,7 +12,9 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
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("<Q", 6966180631402821399)
+44 -1
View File
@@ -4,6 +4,7 @@ Solana client abstraction for blockchain operations.
import asyncio
import json
import struct
from typing import Any
import aiohttp
@@ -23,6 +24,35 @@ from utils.logger import get_logger
logger = get_logger(__name__)
def set_loaded_accounts_data_size_limit(bytes_limit: int) -> 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("<BI", 4, bytes_limit)
return Instruction(COMPUTE_BUDGET_PROGRAM, data, [])
class SolanaClient:
"""Abstraction for Solana RPC client operations."""
@@ -146,6 +176,7 @@ class SolanaClient:
max_retries: int = 3,
priority_fee: int | None = None,
compute_unit_limit: int | None = None,
account_data_size_limit: int | None = None,
) -> str:
"""
Send a transaction with optional priority fee and compute unit limit.
@@ -157,6 +188,8 @@ class SolanaClient:
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 @@ class SolanaClient:
)
# 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))
+3 -1
View File
@@ -186,7 +186,9 @@ class LetsBonkCurveManager(CurveManager):
"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
}
+11 -1
View File
@@ -143,7 +143,17 @@ class LetsBonkEventParser(EventParser):
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}, "
+16 -8
View File
@@ -111,6 +111,9 @@ class PlatformAwareBuyer(Trader):
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 @@ class PlatformAwareBuyer(Trader):
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 @@ class PlatformAwareSeller(Trader):
(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 @@ class PlatformAwareSeller(Trader):
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 @@ class PlatformAwareSeller(Trader):
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)
return self.compute_units.get(operation)