Files
pumpfun-bonkfun-bot_github/CLAUDE.md
T
Anton Sauchyk 02343b775b feat(pumpfun): migrate to buy_v2/sell_v2 and support non-SOL quote assets (#176)
Refresh the vendored IDLs from pump-fun/pump-public-docs @ 9c82f61 and move all
pump.fun trading onto the v2 instruction interface. This is required, not
optional: legacy buy/sell cannot trade coins paired against a quote asset other
than SOL, and USDC is already whitelisted in the on-chain Global account.

Protocol changes absorbed:

- buy_v2 (27 accounts) / sell_v2 (26 accounts) replace the legacy instructions.
  Every account is mandatory and the order is identical for all coins, so the
  conditional cashback/mayhem account lists are gone. Legacy remains available
  via PumpFunInstructionBuilder(use_legacy_instructions=True).
- BondingCurve is 151 bytes: virtual_sol_reserves -> virtual_quote_reserves,
  real_sol_reserves -> real_quote_reserves, plus quote_mint at offset 83. Old
  field names are kept as aliases so existing callers keep working.
- v2 instruction data drops the track_volume OptionBool; amounts are in the
  quote mint's raw units rather than always lamports.
- create_v2 carries a non-SOL quote mint as optional remaining accounts 17-19,
  and CreateEvent gained quote_mint, so extreme_fast_mode can resolve the quote
  asset without an extra fetch.

USDC support: new trade.quote_amounts and filters.allowed_quote_mints config,
accepting "sol"/"usdc" aliases or raw mints. Amounts are per-quote-mint because
1 USDC and 1 SOL are not interchangeable. A coin whose quote mint has no
configured amount is skipped rather than traded at the wrong size, so SOL-only
configs are unaffected.

Bug fixes found while verifying:

- The logs and blocks listeners set no websocket max_size, so any frame over
  1 MiB closed the connection with 1009 and the token in it was lost. Raised
  to 32 MiB.
- PumpSwap priced against the raw quote vault balance, ignoring the new
  Pool.virtual_quote_reserves (i128 at offset 245; live pools are 301 bytes).
  Upstream's note that this field is 0 everywhere is out of date: a live pool
  carries 17.58 SOL against a 148 SOL vault, a 10.15% price error.
- The seller read curve state once at confirmed commitment and silently fell
  back to create-time values, risking a stale creator_vault and ConstraintSeeds.
  It now retries at processed, matching the buyer.
- Account cleanup would burn wrapped SOL when force_burn was set, destroying
  value that closing the account returns. WSOL is now closed without burning.
- The mint scripts treated a landed transaction as a successful one, so a
  reverted buy printed as success. They now assert the on-chain result.

Compute unit limits retuned from mainnet measurements: buy 100k -> 180k,
sell 60k -> 120k. Mint-and-buy is no longer atomic, because create_v2 plus
buy_v2 exceeds the 1232-byte transaction limit; both mint scripts send two
transactions.

Adds learning-examples/pump_v2.py as one shared, standalone v2 toolkit for the
example scripts, and three verification scripts: an offline layout check
against the IDL, a no-funds mainnet simulation, and a live listener matrix that
buys, sells and closes the ATA per listener.

Verified on mainnet: all four listeners (geyser, logs, blocks, pumpportal) and
all eight example scripts completed a real buy, sell and ATA close, each
confirmed by reading the transaction result back rather than trusting
confirmation alone. The USDC path is verified structurally only; no USDC-paired
coin could be found on-chain to exercise it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 17:58:33 +02:00

10 KiB

Pump Bot Development Guide

This is a trading bot for pump.fun and letsbonk.fun platforms that snipes new tokens and implements various trading strategies.

Project Structure

  • src/ - Main source code
  • learning-examples/ - Educational scripts and examples
  • bots/ - Bot configuration files (YAML)
  • logs/ - Log files from bot executions
  • idl/ - Interface definition files for Solana programs

Bash Commands & Development

Setup Commands

# Install dependencies
uv sync

# Activate virtual environment (Unix/macOS)
source .venv/bin/activate

# Install as editable package
uv pip install -e .

Running the Bot

# Run as installed package
pump_bot

# Run directly
uv run src/bot_runner.py

Learning Examples

# Bonding curve status
uv run learning-examples/bonding-curve-progress/get_bonding_curve_status.py TOKEN_ADDRESS

# Listen to migrations
uv run learning-examples/listen-migrations/listen_logsubscribe.py
uv run learning-examples/listen-migrations/listen_blocksubscribe_old_raydium.py

# Compute associated bonding curve
uv run learning-examples/compute_associated_bonding_curve.py

# Listen to new tokens
uv run learning-examples/listen-new-tokens/listen_logsubscribe_abc.py
uv run learning-examples/listen-new-tokens/compare_listeners.py

Verifying pump.fun v2 trade instructions

# Offline: cross-check buy_v2/sell_v2 account layouts, PDA/ATA derivations,
# instruction encoding and quote-asset config against idl/pump_fun_idl.json
uv run learning-examples/verify_v2_account_layout.py

# Mainnet, no funds moved: simulate buy_v2/sell_v2 for one coin, report CU
uv run learning-examples/simulate_v2_trades.py <MINT>

# Mainnet, no funds moved: run the bot's whole buy path against a fresh coin
uv run learning-examples/simulate_bot_buy_path.py
uv run learning-examples/simulate_bot_buy_path.py --no-extreme-fast

Run all three after any pump.fun program upgrade. The simulations report unitsConsumed; use it to retune get_buy_compute_unit_limit / get_sell_compute_unit_limit in platforms/pumpfun/instruction_builder.py.

Code Quality

# Format code
ruff format

# Lint code
ruff check

# Fix linting issues
ruff check --fix

Pump.fun protocol notes (gotchas)

The IDLs under idl/ are vendored verbatim from github.com/pump-fun/pump-public-docs (idl/pump.jsonpump_fun_idl.json, pump_amm.jsonpump_swap_idl.json, pump_fees.json). Refresh them from upstream rather than hand-editing.

Quote assets and the v2 trade instructions (current path)

  • pump.fun supports quote assets other than SOL. BondingCurve.quote_mint is Pubkey::default() (all zeros) for SOL-paired coins; USDC (EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) is whitelisted in Global. Legacy buy/sell cannot trade non-SOL-paired coins at all.
  • The bot uses buy_v2 (27 accounts) and sell_v2 (26 accounts). Every account is mandatory and the order is identical for every coin — SOL or USDC paired, mayhem or not, cashback or not. sell_v2 is buy_v2 minus global_volume_accumulator. Layouts live in _BUY_V2_ACCOUNTS / _SELL_V2_ACCOUNTS in platforms/pumpfun/instruction_builder.py and are machine-checked against the IDL by learning-examples/verify_v2_account_layout.py.
  • v2 args carry no track_volume OptionBool (24-byte data: discriminator + two u64). Volume tracking is unconditional now that user_volume_accumulator is mandatory. max_sol_cost/min_sol_output are in the quote mint's raw units — lamports for SOL, 1e-6 for USDC.
  • Even for SOL-paired coins you must pass wrapped SOL as quote_mint, not Pubkey::default(). Transfers still happen in native SOL, and the associated_quote_* accounts are only seed-constrained — do not create the user's WSOL ATA, it would burn ~0.002 SOL of rent for nothing.
  • Fee recipients: 24 total, in three sets of 8 (NORMAL_FEE_RECIPIENTS, RESERVED_FEE_RECIPIENTS for mayhem coins, BUYBACK_FEE_RECIPIENTS). Every v2 buy/sell needs a fee_recipient and a buyback_fee_recipient.
  • sharing_config (PDA ["sharing-config", base_mint]) lives under the pump fees program, not the pump program. Easy to derive against the wrong program.

BondingCurve account layout

  • The account is 151 bytes: 8-byte discriminator, then virtual_token_reserves, virtual_quote_reserves, real_token_reserves, real_quote_reserves, token_total_supply (u64 each), complete (1B, offset 48), creator (32B, offset 49), is_mayhem_mode (offset 81), is_cashback_coin (offset 82), quote_mint (32B, offset 83), then 36 reserved zero bytes. The documented struct is 115 bytes; the extra 36 are padding.
  • The SOL-named fields were renamed: virtual_sol_reservesvirtual_quote_reserves, real_sol_reservesreal_quote_reserves. The curve manager still exposes the old names as aliases, so pre-existing callers keep working for SOL-paired coins — but anything doing arithmetic must scale by the quote mint's decimals (quote_units_per_token), not a hardcoded 1e9.
  • PumpSwap Pool gained a trailing virtual_quote_reserves: i128 (16 bytes, offset 245). Pool fields end at 261; live accounts are 301 bytes with trailing padding. Quote against effective reserves: pool_quote_token_account.amount + virtual_quote_reserves. Upstream's release note claims it is 0 on all pools — that is out of date. Verified on mainnet: pool 6Bv1JM1deBPe… carries 17.584505433 SOL of virtual reserves against a 148.455 SOL vault, so quoting off the raw vault balance under-prices by ~10.6%. It is i128, not u64 — reading 8 bytes happens to work only while the high half is zero.

Coin creation

  • The IDL instruction is create_v2 (snake_case). Args: name (str), symbol (str), uri (str), creator (pubkey), is_mayhem_mode (bool), is_cashback_enabled (OptionBool 1B). OptionBool is a struct wrapping a single bool — serialized as 1 byte, not 2.
  • create_v2 accounts 1-16 are in the IDL; accounts 17-19 are optional remaining accounts (quote_mint, associated_quote_bonding_curve, quote_token_program) appended only for a non-SOL quote mint. All three or none. This is the only way to read a new coin's quote asset from the instruction rather than the event.
  • extreme_fast_mode skips the curve-state price fetch but still refreshes mayhem/cashback/creator/quote_mint from chain, because the wrong quote mint means spending the wrong balance entirely. Event parsers also populate quote_mint from CreateEvent (which gained quote_mint and virtual_quote_reserves as trailing fields).

Legacy instructions (fallback only)

Retained behind PumpFunInstructionBuilder(..., use_legacy_instructions=True). The IDL under-reports these: buy is 18 accounts on-chain (IDL lists 16) and sell is 16 non-cashback / 17 cashback (IDL lists 14). The extras are bonding-curve-v2 (PDA ["bonding-curve-v2", mint]) followed by a buyback fee recipient (mutable); the cashback sell path also inserts user_volume_accumulator before bonding-curve-v2. Prefer v2 — it is the interface pump.fun maintains.

Code Style & Conventions

Python Style (Ruff Configuration)

  • Line length: 88 characters
  • Indentation: 4 spaces
  • Target Python: 3.11+
  • Quote style: Double quotes
  • Import sorting: Enabled

Linting Rules

  • Security best practices (S)
  • Type annotations (ANN)
  • Exception handling (BLE, TRY)
  • Code complexity (C90)
  • Pylint conventions (PL)
  • No commented-out code (ERA)

Code Organization

  • Imports: Standard library, third-party, local imports
  • Docstrings: Google-style for functions and classes
  • Type hints: Required for all public functions
  • Logging: Use get_logger(__name__) pattern
  • Error handling: Comprehensive try-catch with proper logging

File Structure Patterns

  • __init__.py files for all packages
  • Separate concerns: client, trading, monitoring, platforms
  • Abstract base classes in interfaces/
  • Platform-specific implementations in platforms/

Workflow & Development Practices

Configuration Management

  • Environment variables in .env file
  • Bot configurations in YAML files under bots/
  • Platform detection from config files
  • Validation of platform-listener combinations

Logging

  • Timestamped log files in logs/ directory
  • Format: {bot_name}_{timestamp}.log
  • Different log levels for development vs production
  • Centralized logger utility in utils/logger.py

Trading Architecture

  • Universal trader pattern for platform abstraction
  • Platform-specific implementations (pumpfun, letsbonk)
  • Position tracking and management
  • Priority fee management (dynamic/fixed)

Monitoring Systems

  • Multiple listener types: logs, blocks, geyser, pumpportal
  • Universal listeners with platform abstraction
  • Event parsing and processing
  • Real-time data stream handling

Development Workflow

  1. Make changes to source code
  2. Run ruff check --fix for linting
  3. Run ruff format for formatting
  4. Test with learning examples (standalone scripts) before deploying bots
  5. Use separate processes for production bot instances

Bot Configuration

  • YAML-based configuration files
  • Environment variable interpolation
  • Platform-specific settings
  • Trading parameters (slippage, amounts, timeouts)
  • Filter configurations for token selection
  • Cleanup and account management settings

Testing Strategy

  • Learning examples serve as integration tests
  • Manual testing with learning scripts
  • Configuration validation before bot startup
  • Logging verification for debugging

Key Features

  • Multi-platform support: pump.fun and letsbonk.fun
  • Multiple listening methods: WebSocket logs, block subscription, Geyser
  • Trading strategies: Time-based, take profit/stop loss, manual
  • Priority fee management: Dynamic and fixed fee strategies
  • Account cleanup: Automated token account management
  • Extreme fast mode: Skip validation for faster execution

Security Considerations

  • Private keys stored in environment variables
  • No sensitive data in configuration files
  • Comprehensive input validation
  • Error handling to prevent crashes
  • Rate limiting and retry mechanisms