Files
pumpfun-bonkfun-bot_github/cookbook
ebbfa9f124 chore(deps): upgrade to solders 0.29 / solana 0.40 and bring the rest of the dependencies current (#217)
* chore(deps): upgrade solders to 0.29 and solana to 0.40 in cookbook and tools

solana 0.40 moves TxOpts (now TxOptsModel), MemcmpOpts and TokenAccountOpts
from solana.rpc.types to solana.rpc.core, and spl.token's *Params dataclasses
to spl.token.models as pydantic models — validated and keyword-only. Three
call sites only failed against mainnet: MemcmpOpts.bytes now takes a base58
str, SyncNativeParams was built positionally, and confirm_transaction was
passed a bare "confirmed".

Also moves every cookbook and tools send path off the legacy Transaction onto
VersionedTransaction + MessageV0, and teaches the getTransaction decoder the
json and base64 encodings alongside jsonParsed — the base64 v1 fixture needs
solders 0.29 to deserialize at all.

src/ is untouched and still on the old imports; the offline suite is 3/19
until that lands.

Verified on mainnet: a 0.003 SOL buy_v2/sell_v2 round trip confirmed and the
wallet returned to SOL only, all six listeners and every read-only script run
live, five trade paths simulated with error=None.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(deps): move the bot onto solders 0.29 and solana 0.40

Same three API moves as the cookbook commit, now in src: TxOpts is
TxOptsModel in solana.rpc.core, and spl.token's BurnParams/CloseAccountParams
come from spl.token.models. build_and_send_transaction builds a
VersionedTransaction from MessageV0 with no lookup tables, so the bot no
longer sends a legacy transaction anywhere.

verify_transaction_v1 proved the log route by stripping the logs and expecting
nothing back, which only held while solders could not read a v1 envelope. On
0.29 it can, so the check is inverted: make the envelope unreadable, keep the
logs, and the create must still arrive. A second check pins the envelope
fallback, so a decode regression is reported rather than silently absorbed by
the log route.

Offline: 19/19. Live on mainnet, funds returned:
- tools/simulate_bot_buy_path: zero-RPC buy path, err=None, 107,015 CU
- tools/simulate_v2_trades: buy_v2 95,573 CU, buy+sell 174,190 — both inside
  the existing 180k/120k limits, so no retune
- tools/live_v2_round_trip: buy_v2 + sell_v2 both landed
- tools/live_listener_matrix: all four listeners detected; logs and pumpportal
  ran full round trips; geyser and blocks both drew a coin on an unconfigured
  quote mint and correctly refused to size a buy. Every ATA closed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(deps): bring the rest of the dependencies to current

Every remaining dependency is now at its latest release, with the floors
raised to the versions actually tested rather than the oldest that resolves:

  grpcio        1.73.1 -> 1.84.0    grpcio-tools 1.73.1 -> 1.84.0
  protobuf      6.33.5 -> 7.36.2    uvloop       0.21.0 -> 0.22.1
  pyyaml        6.0.2  -> 6.0.3     python-dotenv 1.2.2 -> 1.2.3
  construct     2.10.70 (floor)     websockets   17.1 (floor)
  ruff          0.12.4 -> 0.16.8

aiohttp and base58 were already current. winloop is left at its old floor:
it is Windows-only and cannot be installed, let alone tested, here.

protobuf 7 arrives with grpcio-tools 1.84 and is the only major. The
committed geyser stubs are gencode 6.31.1 and still pass
ValidateProtobufRuntimeVersion against it; they are not regenerated, because
the committed files import each other absolutely and protoc does not emit
that, so the output would need rewriting. Noted in CLAUDE.md with the
verification date.

ruff 0.16 needs no config change. The repo-wide baseline moves 1680 -> 1713
because the rules moved, not the code; CLAUDE.md carries the new figure so it
is not misread as a regression.

Verified per dependency, not just in aggregate: all four bot configs load
under the new pyyaml/dotenv; the logs, blocks and pumpportal listeners run
under the uvloop policy bot_runner installs; both geyser paths (token
listener and the account-filtered graduation watcher) run under grpcio 1.84 /
protobuf 7. Offline 19/19, including verify_listener_cancellation for
websockets. One more live buy_v2/sell_v2 round trip on the final set, both
landed, ATA closed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(utils): redact RPC credentials from every log record

The provider endpoints carry their API key in the URL and the HTTP clients log
a full request URL at INFO, so anything that raises the root logger to INFO
prints the key. tools/cleanup_accounts.py did, four times, in a terminal.

It was already silencing httpx and httpcore by name. That stopped working the
moment solana-py 0.40 switched to httpx2: the rename took the guard with it
and nothing said so. Naming the clients is now a convenience on top of the
real control — install_secret_redaction masks the value itself, at log-record
creation, whichever logger emits it.

It redacts the *rendered* message rather than record.msg plus the string
arguments. The first version of this did the latter and still leaked: httpx2
passes its URL as a URL object, so the type check skipped the only argument
carrying the key. Confirmed by forcing httpx2 back to INFO and watching the
key print anyway. The host is kept, so a log line still says which provider
answered.

Installed from get_logger, from both logging.basicConfig sites, and from
setup_file_logging before it attaches the handler — logs/ outlives a terminal.

verify_no_rpc_credentials_logged covers all of it, including the non-str
argument. Checked against the defeated version first: it fails there and
passes here. Suite is 20/20.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(agents): make a real bot run the verification, not the simulations

The ground rule said never to run a bot with real funds, which points at the
tools/ harnesses instead. Those call the buyer, seller and listeners directly:
they skip bot_runner, config loading, the trader loop, the exit strategy and
cleanup, so passing there says nothing about the paths only a full run reaches.
Verification is a real run, with explicit approval for that session, covering
every mode the change touches and ending with the wallet holding SOL only.

Also records why a run can look clean when nothing happened: pump_bot runs every
bots/*.yaml, three of the four committed configs ship enabled: false, and with
all of them disabled it prints nothing and exits 0. The log file is the tell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(utils): keep the redaction comment provider-neutral

The parameter list is what matters, not which provider uses which spelling.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 13:28:43 +02:00
..

Cookbook

One script per thing you might want to do on pump.fun, PumpSwap and letsbonk.fun. Each is standalone: run it with uv run <path>, no bot config, no framework. They read .env directly, and most take the mint or curve address as the first argument.

Scripts marked 💸 submit real transactions and spend real funds. Read the module docstring before running one. Everything else only reads.

Naming

Every filename answers three questions before you open it:

<protocol>_<verb>_<noun>[_<variant>].py

pumpfun_buy_token_v2.py              buy one coin, using the v2 instructions
pumpfun_snipe_token_geyser.py        wait for a new coin over Geyser, then buy
pumpfun_listen_tokens_logsubscribe.py   watch for new coins over logsSubscribe
letsbonk_sell_token_exact_out.py     sell for a fixed amount received
  • protocol — pumpfun, pumpswap, letsbonk, solana, anchor. The directory says it too, but a filename on its own is what you see in an editor tab, a grep result or a link.
  • verb — what the script does: buy, sell, create, snipe, listen, watch, read, derive, decode, check, capture, find.
  • noun — what it acts on: token, price, curve, pool, balances, transaction, migrations.
  • variant — the instruction version (v1, v2, exact_in, exact_out) or the transport (geyser, logsubscribe, blocksubscribe, programsubscribe, pumpportal, gettransaction, getaccountinfo).

One script does one thing. Buying and selling are never in the same file. The one exception is pumpfun_create_and_buy_token_v2.py, where the two steps together are the thing people actually ask for — and its name says so.

Fixtures keep their own convention, raw_<what>_from_<method>.json, and sit beside the script that reads them.

Running them

Every script takes its input on the command line, so you never edit a file to try it against your own coin:

uv run cookbook/pumpfun/read/pumpfun_read_price.py <CURVE>
uv run cookbook/pumpfun/trade/pumpfun_buy_token_v2.py <MINT> 0.001 --slippage 0.3
uv run cookbook/pumpswap/pumpswap_buy_token.py <MINT>          # amount defaults

--help works on all of them and lists the defaults. Required values are positional, everything tunable is an option, and the decode scripts default to the fixture beside them so they run with no arguments at all. Nothing is configured by editing a constant or setting an environment variable — .env holds only your endpoints and key.

Shared helpers

The scripts are deliberately repetitive: a script that derives an address inline is easier to read and copy than one that imports a helper you also have to open, so the same twenty lines appear in several files. Two modules are exempt, because both are the kind of thing that must never drift between copies. Neither is runnable, so neither has a verb in its name.

A script that needs one adds its directory to sys.path first; the line is at the top of the file with a comment saying why.

Solana and Anchor basics

Not specific to any of the launchpads below.

Script What it does
solana/solana_read_balances.py Your SOL and every token you hold, across both token programs
solana/solana_check_transaction.py Whether a signature succeeded, reverted, or is not visible yet
solana/solana_read_token2022_mint.py A Token-2022 mint's extensions, and which scaled-UI multiplier is really in force
solana/anchor_calculate_discriminator.py The 8-byte Anchor discriminator for any instruction or account name

pump.fun

Watch for things happening

Script What it does
pumpfun/listen/pumpfun_listen_tokens_logsubscribe.py New coins over logsSubscribe — works on every provider
pumpfun/listen/pumpfun_listen_tokens_blocksubscribe.py New coins over blockSubscribe — whole blocks, slower, not on every provider
pumpfun/listen/pumpfun_listen_tokens_geyser.py New coins over Geyser gRPC — the fastest of the four
pumpfun/listen/pumpfun_listen_tokens_pumpportal.py New coins from PumpPortal's feed — third party, misses some coins
pumpfun/listen/pumpfun_listen_wallet_trades.py One wallet's bonding-curve buys and sells — copy trading
pumpfun/listen/pumpfun_capture_transactions_blocksubscribe.py Save live transactions to disk, to build a fixture

Racing the four listeners against each other is tools/compare_listeners.py.

Read state

Script What it does
pumpfun/read/pumpfun_read_price.py One coin's price, in whatever asset its curve is paired with
pumpfun/read/pumpfun_read_curve.py A curve's full state, decoded field by field
pumpfun/read/pumpfun_watch_curve_progress.py How close a coin is to graduating, polled over time
pumpfun/read/pumpfun_derive_curve_addresses.py Derive a coin's curve and curve ATA offline, under both token programs
pumpfun/read/pumpfun_read_quote_mints.py Every asset a coin may be priced in, --stocks for the tokenized equities

Trade

Script What it does
💸 pumpfun/trade/pumpfun_buy_token_v2.py Buy a coin you name. --dry-run simulates instead of spending
💸 pumpfun/trade/pumpfun_buy_token_exact_quote_v2.py Spend an exact amount of the quote asset. --dry-run simulates
💸 pumpfun/trade/pumpfun_buy_token_exact_sol_in.py Spend an exact amount of SOL. SOL-paired coins only
💸 pumpfun/trade/pumpfun_sell_token_v2.py Sell your whole position in a coin you name
💸 pumpfun/trade/pumpfun_create_token_v2.py Create a coin with create_v2, buying none of it
💸 pumpfun/trade/pumpfun_create_and_buy_token_v2.py Create a coin and buy it
💸 pumpfun/trade/pumpfun_snipe_token_blocksubscribe.py Wait for the next coin created anywhere, then buy it
💸 pumpfun/trade/pumpfun_snipe_token_geyser.py The same snipe, detected over Geyser gRPC
💸 pumpfun/trade/pumpfun_collect_creator_fee_v2.py Sweep the creator fees your coins have accrued
💸 pumpfun/trade/pumpfun_claim_cashback_v2.py Pay out cashback accrued on a pre-2026-09-15 coin

Start at pumpfun_buy_token_v2.py. The two snipers are that same trade behind a listener, which is most of why they are four times longer.

The two buys differ in which side you pin down — buy_v2 fixes the tokens you receive and caps the spend, buy_exact_quote_in_v2 fixes the spend and floors the tokens. Pin the spend when the quote asset is a budget you hold, which is usually the case once a coin is priced in something other than SOL.

Graduation

A coin that fills its bonding curve graduates to the PumpSwap AMM and stops trading on the curve.

Script What it does
pumpfun/graduation/pumpfun_watch_graduating_programsubscribe.py Coins approaching graduation, over a filtered programSubscribe
pumpfun/graduation/pumpfun_watch_graduating_geyser.py The same watch over Geyser gRPC
pumpfun/graduation/pumpfun_listen_migrations_logsubscribe.py Migrations as the wrapper program emits them
pumpfun/graduation/pumpfun_listen_migrations_programsubscribe.py Migrations as new pool accounts appear — noisy

Decode

Each script decodes one kind of payload and falls back to the fixture beside it, so they all run with no arguments and no network. The fixtures are captured from mainnet, never hand-edited — a stale one makes a working decoder look broken.

Script What it does
pumpfun/decode/pumpfun_decode_transaction_gettransaction.py pump.fun instructions inside a getTransaction response
pumpfun/decode/pumpfun_decode_transaction_blocksubscribe.py The same, from a blockSubscribe frame
pumpfun/decode/pumpfun_decode_curve_getaccountinfo.py A bonding curve account's raw bytes

PumpSwap

Where a coin trades after it graduates.

Script What it does
pumpswap/pumpswap_find_pool.py Find a coin's pool and decode it
💸 pumpswap/pumpswap_buy_token.py Buy against the AMM
💸 pumpswap/pumpswap_sell_token.py Sell against the AMM

letsbonk.fun

Built on Raydium LaunchLab, which quotes in two directions: exact in fixes what you spend, exact out fixes what you receive.

Script What it does
💸 letsbonk/letsbonk_buy_token_exact_in.py Spend a fixed amount
💸 letsbonk/letsbonk_buy_token_exact_out.py Receive a fixed number of tokens
💸 letsbonk/letsbonk_sell_token_exact_in.py Sell a fixed number of tokens
💸 letsbonk/letsbonk_sell_token_exact_out.py Sell for a fixed amount received
letsbonk/letsbonk_idl_parser.py Loads the LaunchLab IDL for the four above

legacy

Instructions pump.fun has moved on from. Kept because they still land on chain and older coins were made with them — not what to copy for new work.

Script What it does
💸 legacy/pumpfun_create_and_buy_token_v1.py Create a coin with the pre-Token-2022 create instruction

Not in here

  • tools/ — scripts that exercise the bot rather than teach it: mainnet simulations, live round trips, listener benchmarks, leftover-account cleanup.
  • tests/regression/ — one offline check per bug that has been fixed, each importing the bot's own code. uv run tests/regression/run_all.py.