import asyncio import os import struct import base58 from dotenv import load_dotenv from solana.rpc.async_api import AsyncClient from solana.rpc.commitment import Confirmed from solana.rpc.types import MemcmpOpts, TxOpts from solders.compute_budget import set_compute_unit_limit, set_compute_unit_price 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 VersionedTransaction from spl.token.instructions import get_associated_token_address load_dotenv() RPC_ENDPOINT = os.environ.get("SOLANA_NODE_RPC_ENDPOINT") TOKEN_MINT = Pubkey.from_string("35ySx7Rt3RqeTp75QB81FgRvPT5yDY2m5BupsUYDpump") PRIVATE_KEY = base58.b58decode(os.environ.get("SOLANA_PRIVATE_KEY")) PAYER = Keypair.from_bytes(PRIVATE_KEY) SLIPPAGE = 0.25 # Slippage tolerance TOKEN_DECIMALS = 6 SELL_DISCRIMINATOR = struct.pack(" Pubkey: base_mint_bytes = bytes(base_mint_address) offset = 43 # This should be calculated based on the fields before the base_mint field filters = [ MemcmpOpts(offset=offset, bytes=base_mint_bytes) ] response = await client.get_program_accounts( amm_program_id, encoding="jsonParsed", filters=filters ) market_address = [account.pubkey for account in response.value][0] return market_address async def get_market_data(client: AsyncClient, market_address: Pubkey): response = await client.get_account_info_json_parsed(market_address) data = response.value.data parsed_data = {} offset = 8 fields = [ ("pool_bump", "u8"), ("index", "u16"), ("creator", "pubkey"), ("base_mint", "pubkey"), ("quote_mint", "pubkey"), ("lp_mint", "pubkey"), ("pool_base_token_account", "pubkey"), ("pool_quote_token_account", "pubkey"), ("lp_supply", "u64"), ] for field_name, field_type in fields: if field_type == "pubkey": value = data[offset:offset + 32] parsed_data[field_name] = base58.b58encode(value).decode("utf-8") offset += 32 elif field_type in {"u64", "i64"}: value = struct.unpack(" float: base_balance_resp = await client.get_token_account_balance(pool_base_token_account) quote_balance_resp = await client.get_token_account_balance(pool_quote_token_account) base_amount = float(base_balance_resp.value.ui_amount) quote_amount = float(quote_balance_resp.value.ui_amount) token_price = quote_amount / base_amount return token_price def create_ata_idempotent_ix(payer_pubkey, owner_pubkey) -> Instruction: """ Create an instruction to create an Associated Token Account for WSOL in an idempotent way. """ associated_token_address = get_associated_token_address(owner_pubkey, SOL) instruction_accounts = [ AccountMeta(pubkey=payer_pubkey, is_signer=True, is_writable=True), AccountMeta(pubkey=associated_token_address, is_signer=False, is_writable=True), AccountMeta(pubkey=owner_pubkey, is_signer=False, is_writable=False), AccountMeta(pubkey=SOL, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, is_signer=False, is_writable=False), ] data = bytes([1]) return Instruction(SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM, data, instruction_accounts) async def sell_pump_swap(client: AsyncClient, pump_fun_amm_pool: Pubkey, payer: Keypair, base_mint: Pubkey, user_base_token_account: Pubkey, user_quote_token_account: Pubkey, pool_base_token_account: Pubkey, pool_quote_token_account: Pubkey, slippage: float = 0.25): # Get token balance token_balance = int((await client.get_token_account_balance(user_base_token_account)).value.amount) token_balance_decimal = token_balance / 10**TOKEN_DECIMALS print(f"Token balance: {token_balance_decimal}") if token_balance == 0: print("No tokens to sell.") return # Calculate token price token_price_sol = await calculate_token_pool_price(client, pool_base_token_account, pool_quote_token_account) print(f"Price per Token: {token_price_sol:.20f} SOL") # Calculate minimum SOL output amount = token_balance min_sol_output = float(token_balance_decimal) * float(token_price_sol) slippage_factor = 1 - slippage min_sol_output = int((min_sol_output * slippage_factor) * LAMPORTS_PER_SOL) print(f"Selling {token_balance_decimal} tokens") print(f"Minimum SOL output: {min_sol_output / LAMPORTS_PER_SOL:.10f} SOL") accounts = [ AccountMeta(pubkey=pump_fun_amm_pool, is_signer=False, is_writable=False), AccountMeta(pubkey=payer.pubkey(), is_signer=True, is_writable=True), AccountMeta(pubkey=PUMP_SWAP_GLOBAL_CONFIG, is_signer=False, is_writable=False), AccountMeta(pubkey=base_mint, is_signer=False, is_writable=False), AccountMeta(pubkey=SOL, is_signer=False, is_writable=False), AccountMeta(pubkey=user_base_token_account, is_signer=False, is_writable=True), AccountMeta(pubkey=user_quote_token_account, is_signer=False, is_writable=True), AccountMeta(pubkey=pool_base_token_account, is_signer=False, is_writable=True), AccountMeta(pubkey=pool_quote_token_account, is_signer=False, is_writable=True), AccountMeta(pubkey=PUMP_PROTOCOL_FEE_RECIPIENT, is_signer=False, is_writable=False), AccountMeta(pubkey=PUMP_PROTOCOL_FEE_RECIPIENT_TOKEN_ACCOUNT, is_signer=False, is_writable=True), AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_TOKEN_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSTEM_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM, is_signer=False, is_writable=False), AccountMeta(pubkey=PUMP_SWAP_EVENT_AUTHORITY, is_signer=False, is_writable=False), AccountMeta(pubkey=PUMP_AMM_PROGRAM_ID, is_signer=False, is_writable=False), ] data = SELL_DISCRIMINATOR + struct.pack("