diff --git a/learning-examples/manual_buy_cu_optimized.py b/learning-examples/manual_buy_cu_optimized.py index fe831b2..cdc6148 100644 --- a/learning-examples/manual_buy_cu_optimized.py +++ b/learning-examples/manual_buy_cu_optimized.py @@ -1,3 +1,15 @@ +""" +Pump.fun Token Buy Script with Compute Unit Optimization + +This script is identical to manual_buy.py but adds SetLoadedAccountsDataSizeLimit +instruction. By default, Solana transactions can load up to 64MB of account data +(costing 16k CU). By setting a lower limit (512KB), we reduce CU consumption and +improve transaction priority. + +Key difference from manual_buy.py: +- Adds set_loaded_accounts_data_size_limit(512_000) before other instructions +""" + import asyncio import base64 import hashlib @@ -16,7 +28,7 @@ from solders.instruction import AccountMeta, Instruction from solders.keypair import Keypair from solders.message import Message from solders.pubkey import Pubkey -from solders.transaction import Transaction +from solders.transaction import Transaction, VersionedTransaction from spl.token.instructions import ( create_idempotent_associated_token_account, get_associated_token_address, @@ -61,10 +73,14 @@ class BondingCurveState: ) def __init__(self, data: bytes) -> None: + """Parse bonding curve data.""" if data[:8] != EXPECTED_DISCRIMINATOR: raise ValueError("Invalid curve state discriminator") + parsed = self._STRUCT.parse(data[8:]) self.__dict__.update(parsed) + + # Convert raw bytes to Pubkey for creator field if hasattr(self, "creator") and isinstance(self.creator, bytes): self.creator = Pubkey.from_bytes(self.creator) @@ -75,15 +91,18 @@ async def get_pump_curve_state( response = await conn.get_account_info(curve_address, encoding="base64") if not response.value or not response.value.data: raise ValueError("Invalid curve state: No data") + data = response.value.data if data[:8] != EXPECTED_DISCRIMINATOR: raise ValueError("Invalid curve state discriminator") + return BondingCurveState(data) def calculate_pump_curve_price(curve_state: BondingCurveState) -> float: if curve_state.virtual_token_reserves <= 0 or curve_state.virtual_sol_reserves <= 0: raise ValueError("Invalid reserve state") + return (curve_state.virtual_sol_reserves / LAMPORTS_PER_SOL) / ( curve_state.virtual_token_reserves / 10**TOKEN_DECIMALS ) @@ -91,130 +110,53 @@ def calculate_pump_curve_price(curve_state: BondingCurveState) -> float: def _find_creator_vault(creator: Pubkey) -> Pubkey: derived_address, _ = Pubkey.find_program_address( - [b"creator-vault", bytes(creator)], PUMP_PROGRAM + [b"creator-vault", bytes(creator)], + PUMP_PROGRAM, ) return derived_address def _find_global_volume_accumulator() -> Pubkey: derived_address, _ = Pubkey.find_program_address( - [b"global_volume_accumulator"], PUMP_PROGRAM + [b"global_volume_accumulator"], + PUMP_PROGRAM, ) return derived_address def _find_user_volume_accumulator(user: Pubkey) -> Pubkey: derived_address, _ = Pubkey.find_program_address( - [b"user_volume_accumulator", bytes(user)], PUMP_PROGRAM + [b"user_volume_accumulator", bytes(user)], + PUMP_PROGRAM, ) return derived_address def _find_fee_config() -> Pubkey: derived_address, _ = Pubkey.find_program_address( - [b"fee_config", bytes(PUMP_PROGRAM)], PUMP_FEE_PROGRAM + [b"fee_config", bytes(PUMP_PROGRAM)], + PUMP_FEE_PROGRAM, ) return derived_address def set_loaded_accounts_data_size_limit(bytes_limit: int) -> Instruction: - """Create SetLoadedAccountsDataSizeLimit compute budget instruction.""" + """ + Create SetLoadedAccountsDataSizeLimit instruction to reduce CU consumption. + + Solana defaults to 64MB loaded data limit (16k CU cost: 8 CU per 32KB). + By setting a lower limit, you reduce CU consumption and improve tx priority. + + Args: + bytes_limit: Max account data size in bytes (e.g., 512_000 = 512KB) + + Returns: + Compute Budget instruction (discriminator 4) + """ data = struct.pack("