import asyncio import json import base64 import struct import base58 import os from solana.transaction import Message from solana.rpc.async_api import AsyncClient from solana.rpc.commitment import Confirmed from solana.rpc.types import TxOpts from solders.pubkey import Pubkey from solders.keypair import Keypair from solders.instruction import Instruction, AccountMeta from solders.system_program import TransferParams, transfer from solders.transaction import VersionedTransaction, Transaction from solders.compute_budget import set_compute_unit_price import spl.token.instructions as spl_token from spl.token.instructions import get_associated_token_address import websockets import hashlib from construct import Struct, Int64ul, Flag # Here and later all the discriminators are precalculated. See learning-examples/discriminator.py EXPECTED_DISCRIMINATOR = struct.pack(" None: parsed = self._STRUCT.parse(data[8:]) self.__dict__.update(parsed) async def get_pump_curve_state(conn: AsyncClient, curve_address: Pubkey) -> BondingCurveState: response = await conn.get_account_info(curve_address) 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) async def buy_token(mint: Pubkey, bonding_curve: Pubkey, associated_bonding_curve: Pubkey, amount: float, slippage: float = 0.25, max_retries=5): private_key = base58.b58decode("ENTER_PRIVATE_KEY") payer = Keypair.from_bytes(private_key) async with AsyncClient(RPC_ENDPOINT) as client: associated_token_account = get_associated_token_address(payer.pubkey(), mint) amount_lamports = int(amount * LAMPORTS_PER_SOL) # Fetch the token price curve_state = await get_pump_curve_state(client, bonding_curve) token_price_sol = calculate_pump_curve_price(curve_state) token_amount = amount / token_price_sol # Calculate maximum SOL to spend with slippage max_amount_lamports = int(amount_lamports * (1 + slippage)) # Create associated token account with retries for ata_attempt in range(max_retries): try: account_info = await client.get_account_info(associated_token_account) if account_info.value is None: print(f"Creating associated token account (Attempt {ata_attempt + 1})...") create_ata_ix = spl_token.create_associated_token_account( payer=payer.pubkey(), owner=payer.pubkey(), mint=mint ) msg = Message([create_ata_ix], payer.pubkey()) tx_ata = await client.send_transaction( Transaction([payer], msg, (await client.get_latest_blockhash()).value.blockhash), opts=TxOpts(skip_preflight=True, preflight_commitment=Confirmed) ) await client.confirm_transaction(tx_ata.value, commitment="confirmed") print("Associated token account created.") print(f"Associated token account address: {associated_token_account}") break else: print("Associated token account already exists.") print(f"Associated token account address: {associated_token_account}") break except Exception as e: print(f"Attempt {ata_attempt + 1} to create associated token account failed: {str(e)}") if ata_attempt < max_retries - 1: wait_time = 2 ** ata_attempt print(f"Retrying in {wait_time} seconds...") await asyncio.sleep(wait_time) else: print("Max retries reached. Unable to create associated token account.") return # Continue with the buy transaction for attempt in range(max_retries): try: accounts = [ AccountMeta(pubkey=PUMP_GLOBAL, is_signer=False, is_writable=False), AccountMeta(pubkey=PUMP_FEE, is_signer=False, is_writable=True), AccountMeta(pubkey=mint, is_signer=False, is_writable=False), AccountMeta(pubkey=bonding_curve, is_signer=False, is_writable=True), AccountMeta(pubkey=associated_bonding_curve, is_signer=False, is_writable=True), AccountMeta(pubkey=associated_token_account, is_signer=False, is_writable=True), AccountMeta(pubkey=payer.pubkey(), is_signer=True, is_writable=True), AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_RENT, is_signer=False, is_writable=False), AccountMeta(pubkey=PUMP_EVENT_AUTHORITY, is_signer=False, is_writable=False), AccountMeta(pubkey=PUMP_PROGRAM, is_signer=False, is_writable=False), ] discriminator = struct.pack("