Skip to content

Commit b6928d1

Browse files
authored
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
1 parent ec6d586 commit b6928d1

File tree

10 files changed

+108
-13
lines changed

10 files changed

+108
-13
lines changed

bots/bot-sniper-1-geyser.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ compute_units:
5757
# buy: 100_000 # Buy operations (ATA creation + trading)
5858
# sell: 60_000 # Sell operations (just trading)
5959

60+
# Account data size optimization (reduces CU cost and improves tx priority)
61+
# Reduces CU cost from 16k to ~128 CU by limiting loaded account data.
62+
# Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead.
63+
# Note: Savings don't show in "consumed CU" but improve tx priority/cost.
64+
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
65+
account_data_size: 512_000 # 512KB limit
66+
6067
# Filters for token selection
6168
filters:
6269
match_string: null # Only process tokens with this string in name/symbol

bots/bot-sniper-2-logs.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ compute_units:
5757
# buy: 100_000 # Buy operations (ATA creation + trading)
5858
# sell: 60_000 # Sell operations (just trading)
5959

60+
# Account data size optimization (reduces CU cost and improves tx priority)
61+
# Reduces CU cost from 16k to ~128 CU by limiting loaded account data.
62+
# Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead.
63+
# Note: Savings don't show in "consumed CU" but improve tx priority/cost.
64+
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
65+
account_data_size: 512_000 # 512KB limit
66+
6067
# Filters for token selection
6168
filters:
6269
match_string: null # Only process tokens with this string in name/symbol

bots/bot-sniper-3-blocks.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ compute_units:
5757
# buy: 100_000 # Buy operations (ATA creation + trading)
5858
# sell: 60_000 # Sell operations (just trading)
5959

60+
# Account data size optimization (reduces CU cost and improves tx priority)
61+
# Reduces CU cost from 16k to ~128 CU by limiting loaded account data.
62+
# Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead.
63+
# Note: Savings don't show in "consumed CU" but improve tx priority/cost.
64+
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
65+
account_data_size: 512_000 # 512KB limit
66+
6067
# Filters for token selection
6168
filters:
6269
match_string: null # Only process tokens with this string in name/symbol

bots/bot-sniper-4-pp.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ compute_units:
5555
# buy: 100_000 # Buy operations (ATA creation + trading)
5656
# sell: 60_000 # Sell operations (just trading)
5757

58+
# Account data size optimization (reduces CU cost and improves tx priority)
59+
# Reduces CU cost from 16k to ~128 CU by limiting loaded account data.
60+
# Default is 64MB (16k CU). Setting to 512KB significantly reduces overhead.
61+
# Note: Savings don't show in "consumed CU" but improve tx priority/cost.
62+
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
63+
account_data_size: 512_000 # 512KB limit
64+
5865
# Filters for token selection
5966
filters:
6067
match_string: null # Only process tokens with this string in name/symbol

learning-examples/bonding-curve-progress/poll_bonding_curve_progress.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
# Constants
1818
RPC_URL: Final[str] = os.getenv("SOLANA_NODE_RPC_ENDPOINT")
19-
TOKEN_MINT: Final[str] = "YOUR_TOKEN_MINT_ADDRESS_HERE" # Replace with actual token mint address
19+
TOKEN_MINT: Final[str] = (
20+
"YOUR_TOKEN_MINT_ADDRESS_HERE" # Replace with actual token mint address
21+
)
2022
PUMP_PROGRAM_ID: Final[Pubkey] = Pubkey.from_string(
2123
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"
2224
)

learning-examples/fetch_price.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
LAMPORTS_PER_SOL: Final[int] = 1_000_000_000
1414
TOKEN_DECIMALS: Final[int] = 6
15-
CURVE_ADDRESS: Final[str] = "YOUR_BONDING_CURVE_ADDRESS_HERE" # Replace with actual bonding curve address
15+
CURVE_ADDRESS: Final[str] = (
16+
"YOUR_BONDING_CURVE_ADDRESS_HERE" # Replace with actual bonding curve address
17+
)
1618

1719
# Here and later all the discriminators are precalculated. See learning-examples/calculate_discriminator.py
1820
EXPECTED_DISCRIMINATOR: Final[bytes] = struct.pack("<Q", 6966180631402821399)

src/core/client.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import asyncio
66
import json
7+
import struct
78
from typing import Any
89

910
import aiohttp
@@ -23,6 +24,35 @@
2324
logger = get_logger(__name__)
2425

2526

27+
def set_loaded_accounts_data_size_limit(bytes_limit: int) -> Instruction:
28+
"""
29+
Create SetLoadedAccountsDataSizeLimit instruction to reduce CU consumption.
30+
31+
By default, Solana transactions can load up to 64MB of account data,
32+
costing 16k CU (8 CU per 32KB). Setting a lower limit reduces CU
33+
consumption and improves transaction priority.
34+
35+
NOTE: CU savings are NOT visible in "consumed CU" metrics, which only
36+
show execution CU. The 16k CU loaded accounts overhead is counted
37+
separately for transaction priority/cost calculation.
38+
39+
Args:
40+
bytes_limit: Max account data size in bytes (e.g., 512_000 = 512KB)
41+
42+
Returns:
43+
Compute Budget instruction with discriminator 4
44+
45+
Reference:
46+
https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
47+
"""
48+
COMPUTE_BUDGET_PROGRAM = Pubkey.from_string(
49+
"ComputeBudget111111111111111111111111111111"
50+
)
51+
52+
data = struct.pack("<BI", 4, bytes_limit)
53+
return Instruction(COMPUTE_BUDGET_PROGRAM, data, [])
54+
55+
2656
class SolanaClient:
2757
"""Abstraction for Solana RPC client operations."""
2858

@@ -146,6 +176,7 @@ async def build_and_send_transaction(
146176
max_retries: int = 3,
147177
priority_fee: int | None = None,
148178
compute_unit_limit: int | None = None,
179+
account_data_size_limit: int | None = None,
149180
) -> str:
150181
"""
151182
Send a transaction with optional priority fee and compute unit limit.
@@ -157,6 +188,8 @@ async def build_and_send_transaction(
157188
max_retries: Maximum number of retry attempts.
158189
priority_fee: Optional priority fee in microlamports.
159190
compute_unit_limit: Optional compute unit limit. Defaults to 85,000 if not provided.
191+
account_data_size_limit: Optional account data size limit in bytes (e.g., 512_000).
192+
Reduces CU cost from 16k to ~128 CU. Must be first instruction.
160193
161194
Returns:
162195
Transaction signature.
@@ -168,9 +201,19 @@ async def build_and_send_transaction(
168201
)
169202

170203
# Add compute budget instructions if applicable
171-
if priority_fee is not None or compute_unit_limit is not None:
204+
if (
205+
priority_fee is not None
206+
or compute_unit_limit is not None
207+
or account_data_size_limit is not None
208+
):
172209
fee_instructions = []
173210

211+
if account_data_size_limit is not None:
212+
fee_instructions.append(
213+
set_loaded_accounts_data_size_limit(account_data_size_limit)
214+
)
215+
logger.info(f"Account data size limit: {account_data_size_limit} bytes")
216+
174217
# Set compute unit limit (use provided value or default to 85,000)
175218
cu_limit = compute_unit_limit if compute_unit_limit is not None else 85_000
176219
fee_instructions.append(set_compute_unit_limit(cu_limit))

src/platforms/letsbonk/curve_manager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ def _decode_pool_state_with_idl(self, data: bytes) -> dict[str, Any]:
186186
"real_quote": decoded_pool_state.get("real_quote", 0),
187187
"status": decoded_pool_state.get("status", 0),
188188
"supply": decoded_pool_state.get("supply", 0),
189-
"creator": decoded_pool_state.get("creator"), # Creator pubkey (as base58 string)
189+
"creator": decoded_pool_state.get(
190+
"creator"
191+
), # Creator pubkey (as base58 string)
190192
"base_vault": decoded_pool_state.get("base_vault"), # Base vault pubkey
191193
"quote_vault": decoded_pool_state.get("quote_vault"), # Quote vault pubkey
192194
}

src/platforms/letsbonk/event_parser.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,17 @@ def get_account_key(index):
143143
base_vault = get_account_key(8) # base_vault account
144144
quote_vault = get_account_key(9) # quote_vault account
145145

146-
if not all([creator, global_config, platform_config, pool_state, base_mint, base_vault, quote_vault]):
146+
if not all(
147+
[
148+
creator,
149+
global_config,
150+
platform_config,
151+
pool_state,
152+
base_mint,
153+
base_vault,
154+
quote_vault,
155+
]
156+
):
147157
logger.debug(
148158
f"Missing required accounts: creator={creator}, global_config={global_config}, "
149159
f"platform_config={platform_config}, pool_state={pool_state}, base_mint={base_mint}, "

src/trading/platform_aware.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ async def execute(self, token_info: TokenInfo) -> TradeResult:
111111
compute_unit_limit=instruction_builder.get_buy_compute_unit_limit(
112112
self._get_cu_override("buy", token_info.platform)
113113
),
114+
account_data_size_limit=self._get_cu_override(
115+
"account_data_size", token_info.platform
116+
),
114117
)
115118

116119
success = await self.client.confirm_transaction(tx_signature)
@@ -154,17 +157,17 @@ def _get_pool_address(
154157

155158
def _get_cu_override(self, operation: str, platform: Platform) -> int | None:
156159
"""Get compute unit override from configuration.
157-
160+
158161
Args:
159162
operation: "buy" or "sell"
160163
platform: Trading platform (unused - each config is platform-specific)
161-
164+
162165
Returns:
163166
CU override value if configured, None otherwise
164167
"""
165168
if not self.compute_units:
166169
return None
167-
170+
168171
# Just check for operation override (buy/sell)
169172
return self.compute_units.get(operation)
170173

@@ -234,7 +237,9 @@ async def execute(self, token_info: TokenInfo) -> TradeResult:
234237
(expected_sol_output * (1 - self.slippage)) * LAMPORTS_PER_SOL
235238
)
236239

237-
logger.info(f"Selling {token_balance_decimal} tokens on {token_info.platform.value}")
240+
logger.info(
241+
f"Selling {token_balance_decimal} tokens on {token_info.platform.value}"
242+
)
238243
logger.info(f"Expected SOL output: {expected_sol_output:.8f} SOL")
239244
logger.info(
240245
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:
266271
compute_unit_limit=instruction_builder.get_sell_compute_unit_limit(
267272
self._get_cu_override("sell", token_info.platform)
268273
),
274+
account_data_size_limit=self._get_cu_override(
275+
"account_data_size", token_info.platform
276+
),
269277
)
270278

271279
success = await self.client.confirm_transaction(tx_signature)
@@ -309,16 +317,16 @@ def _get_pool_address(
309317

310318
def _get_cu_override(self, operation: str, platform: Platform) -> int | None:
311319
"""Get compute unit override from configuration.
312-
320+
313321
Args:
314322
operation: "buy" or "sell"
315323
platform: Trading platform (unused - each config is platform-specific)
316-
324+
317325
Returns:
318326
CU override value if configured, None otherwise
319327
"""
320328
if not self.compute_units:
321329
return None
322-
330+
323331
# Just check for operation override (buy/sell)
324-
return self.compute_units.get(operation)
332+
return self.compute_units.get(operation)

0 commit comments

Comments
 (0)