Verified every claim in CLAUDE.md against the code after the recent debugging,
IDL, bot, and learning-example updates. Four were wrong:
- The dependency chain listed `utils` before `interfaces`, but
utils/idl_manager.py imports interfaces.core and interfaces imports nothing
internal. It also made trading and monitoring peers when trading imports
monitoring, and omitted cleanup and geyser entirely.
- Ruff baseline said ~2400 errors; `uv run ruff check` reports 1676.
- `live_*` was presented as the marker for scripts that spend real funds. Only
2 of the 13 scripts that submit transactions carry that prefix — manual_*,
mint_and_buy* and cleanup_accounts.py spend too.
- compare_listeners.py was cited without its path, ambiguous against
listen-migrations/compare_migration_listeners.py.
The protocol section (v2 account counts, BondingCurve offsets, PumpSwap i128,
PDA seeds, fee-recipient sets, tx-status rules) checks out against
idl/pump_fun_idl.json and src/; both offline verifiers still pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Move the "Also by Chainstack" callout back to its original position
just below the walkthrough link, in its original blockquote style, so
it stays visible without scrolling. The previous README rewrite had
relocated it to the bottom of the file.
Note that the linked walkthrough doc lags behind the code, and point
readers at the README for setup and configuration instead.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Before: BC fetch in extreme_fast_mode used default (confirmed) commitment
and retried up to 10 times with growing backoff (~10s total). Geyser/logs
fire on processed, so the BC isn't yet at confirmed commitment when the
bot reads it — most fetches failed and burned the full retry budget,
adding ~10s to detect→confirmed.
After: read at processed commitment to match the listener event horizon,
and cap retries at 4 with 150ms gaps (~600ms ceiling). Most reads succeed
on the first attempt.
Mainnet benchmark (n=4 successful buys, geyser listener):
buy_slot − create_slot: min=2 median=3 max=9 (~0.8s — 3.6s on chain)
wall detect→confirmed: median 2-3s (1s resolution)
Best case 2 slots = next slot after creation + tx propagation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related fixes from mainnet validation of geyser/logs/blocks/pumpportal:
1. extreme_fast_mode buys previously skipped the BC fetch entirely. After
the 2026-04-28 cutover, fee_recipient (mayhem mode) and creator_vault
(PFEE-delegated BC.creator) cannot be derived from listener-side data
alone — the program rejects with NotAuthorized (0x1770) /
ConstraintSeeds (0x7d6). Add a short retry loop that fetches the curve
state once before submitting the buy, so the instruction builder picks
the correct fee_recipient and creator_vault. The ~150ms cost is small
relative to a failed tx and 5s sell wait.
2. LetsBonkPumpPortalProcessor returned TokenInfo without token_program_id.
The universal builder then defaulted to Token-2022 and the buy failed
with IncorrectProgramId at GetAccountDataSize on the user-ATA create
ix. LetsBonk tokens are predominantly regular SPL Token, so default to
TOKEN_PROGRAM in the processor.
Note: the pumpportal listener still has unrelated data-race issues (the
PumpPortal stream sometimes fires before the on-chain BC is RPC-readable,
and bondingCurveKey occasionally references a different mint than the
detected token). These predate the 2026-04-28 cutover and need a separate
fix (e.g., verifying mint+BC consistency on the tx side before submit).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Post-2026-04-28, BC.creator can be delegated to a PFEE-program-owned PDA
after the initial creator buy. The create-time creator_vault cached on
TokenInfo goes stale before the sell lands, producing ConstraintSeeds
(0x7d6) on the Sell instruction.
The sell flow already re-fetches pool_state to refresh is_mayhem_mode and
is_cashback_coin; extend it to also refresh token_info.creator and re-derive
creator_vault from the current BC.creator.
Mainnet validation: geyser listener buy+sell on BEE — buy 2TSqZHZh…k7uN,
sell 3TevcP5g…f8nQ, err=None on both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two bugs found by mainnet validation post-2026-04-28 cutover:
1. Blocks listener processed failed txs, including failed create_v2s. The
bot then tried to buy a non-existent mint (InvalidMint at ATA creation).
Fix: filter `meta.err is not None` in _process_block_transactions.
2. Blocks listener parsed `args.creator` from the create_v2 ix payload to
derive creator_vault. Post-cutover, BC.creator is sometimes set to a
PFEE-program-owned PDA distinct from args.creator (e.g., Companions:
args.creator=DdZG8dw, BC.creator=3hPZm9). The Anchor seeds constraint
on creator_vault then fails with ConstraintSeeds (0x7d6). Fix: in
parse_token_creation_from_block, prefer parsing the CreateEvent log
(which carries the canonical creator the program wrote to BC.creator)
over args.creator from the ix payload.
Mainnet validation:
- buy 2uBrNqqW…bPDG, sell 32EKJjrK…9fXv on PUMP (Pumpcoin), err=None.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three small ergonomic fixes uncovered while running every learning
example end-to-end:
copytrading/listen_wallet_transactions.py
Was hardcoded to WALLET_TO_TRACK = "...". Now accepts argv[1] so
you can run it without editing the file.
pumpswap/get_pumpswap_pools.py
Same pattern (TOKEN_MINT placeholder) and the underlying
getProgramAccounts call would also time out at the default 30s
on busy mainnet RPCs — bumped both AsyncClient timeouts to 120s.
bonding-curve-progress/get_graduating_tokens.py
Bumped RPC timeout 120s → 240s for the same reason. The threshold
scan over all pump.fun bonding curves still occasionally exceeds
even that on overloaded RPCs (it's a known-heavy query); a smaller
threshold or memcmp-narrowed filter is the proper long-term fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PumpSwap (manual_buy_pumpswap.py / manual_sell_pumpswap.py)
- Real on-chain pump-swap buys use 24 accounts; the IDL is incomplete
(lists 23). Missing 24th account is pool-v2 PDA, derived from seed
["pool-v2", base_mint] under the pump-amm program.
- Without it, pump-amm throws AnchorError 6023 (Overflow) at buy.rs:400/414
after the trade transfers complete (the source of the earlier "pre-existing
overflow" — was actually a missing account, not a math bug).
- find_pool_v2(base_mint) added; appended to both buy and sell account lists
after fee_program. The April-28 breaking-fee accounts (still gated behind
INCLUDE_BREAKING_FEE_ACCOUNTS) come after pool-v2 — matching the doc's
"All accounts till bonding-curve-v2 and pool-v2 remain the same."
- AsyncClient timeout bumped to 120s so the heavy getProgramAccounts pool
lookup doesn't time out on slower RPC paths.
- Live-verified on mainnet with 9PwadsGz...pump:
buy 2xgdJJsDMzoMyxJzrCATKwGfpX7M... err=None (24 accounts)
sell 4vdBkGpCMQYEWncj5k1suGzKPUMQ... err=None (24 accounts)
manual_buy_geyser.py
- Fixes IndexError when create tx references ALT-loaded keys
(matches the same fix applied to manual_buy.py).
- Re-enables the 15s sleep + on-chain price/fee_recipient lookup that
were commented out for testing — needed for buys on real pools.
- Live-verified: 45wSgX2Pu1LLZWLgu3e9qdhRaGJjqwMqQP5HdeV7zMBqNXziB2uEgxQd5bAqvAhBLFnAqzbuK3LAWowhxZxdemJ
(18-account buy, err=None) on Token-2022 cashback-enabled INSIDER mint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends the 2026-04-28 program-upgrade prep (commit c25e2ed) to the
remaining trade scripts:
mint_and_buy.py — 18-account buy after bonding-curve-v2.
Tested live with a fresh TEST mint (Solscan
sig 62EZFCKVuxvqmzj...), succeeded.
mint_and_buy_v2.py — 18-account buy. Tested live with a
mayhem-mode TEST2 token (Token-2022 + 5
mayhem accounts), Solscan sig 44SvQSrhmHy...,
succeeded.
pumpswap/manual_buy_pumpswap.py / manual_sell_pumpswap.py
— Adds the 2 new pump-swap accounts (fee
recipient + its quote-mint ATA) gated behind
INCLUDE_BREAKING_FEE_ACCOUNTS = False; flip
to True after 2026-04-28 16:00 UTC.
Pre-existing program-side overflow at
buy.rs:400 (AnchorError 6023) flagged in
a comment — affects current pump-swap
buys, unrelated to this upgrade.
Both pumpswap scripts now also accept TOKEN_MINT via argv[1].
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pump.fun program upgrade scheduled for 2026-04-28 16:00 UTC adds one new
mutable account (one of 8 fee recipients) at the end of buy/sell ixs,
after bonding-curve-v2. The new format is already accepted on mainnet
ahead of the cutover, so applying now keeps scripts working on both
sides of the upgrade.
Doc: github.com/pump-fun/pump-public-docs/blob/main/docs/BREAKING_FEE_RECIPIENT.md
Per file:
manual_buy.py — 18-account buy. Also fixes a pre-existing
listener crash on Address-Lookup-Table create
txs (skips them) and adds bool/OptionBool
handling to decode_create_instruction so
create_v2 doesn't raise on its trailing args.
manual_buy_cu_optimized.py — 18-account buy. Bumps the CU-optimization
account-data limit to 16MB (tested) — older
values trigger MaxLoadedAccountsDataSizeExceeded
on Token-2022/cashback coins. Same listener
ALT-skip and decoder bool fixes.
manual_buy_geyser.py — 18-account buy. Re-enables price calculation
and mayhem-mode-aware fee_recipient detection
(was scaffolded out for testing).
manual_sell.py — 16-account non-cashback / 17-account cashback
sell. Reads is_cashback_coin from BC byte 82
and inserts user_volume_accumulator before
bonding-curve-v2 when needed. TOKEN_MINT now
accepts argv[1] override.
Live-verified on mainnet:
buy manual_buy.py 3AVnLC3sdBD598cs3... + 3bWU9bB8U9aemA2BFhS2...
buy manual_buy_cu_optimized 2PfH5rHw62o3KkQ3N4z8...
sell manual_sell.py 3E7dyPBPBRe95BtPQXmb... + 5L4wWSzPV36m6XqXAswB...
All four show the expected 18 (buy) / 16 (sell non-cashback) account count
with one of the 8 BREAKING_FEE_RECIPIENTS as the trailing mutable account.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refreshes the read-only learning examples (Phase A3) against the post
Feb–Apr 2026 IDL changes:
- CreateEvent now has 15 fields (timestamp, 4×u64 reserves, token_program,
is_mayhem_mode, is_cashback_enabled). Listener parsers were truncating
after `creator`; the v2 ones were also reading is_mayhem_mode at the
wrong offset.
- BondingCurve account is now 83 bytes (added is_cashback_coin).
- PumpSwap Pool account is now 245 bytes (added is_cashback_coin) — the
listen_programsubscribe dataSize filter was matching nothing.
- IDL instruction `createV2` was renamed to `create_v2`; the legacy
`create` instruction added a `creator: pubkey` arg in March 2026.
- decode_from_blockSubscribe.py decoder now handles bool, i64, u32, u16,
u8, and the OptionBool defined type (1-byte wire format).
Files touched (all under learning-examples/):
bonding-curve-progress/get_bonding_curve_status.py — V4 struct (cashback)
bonding-curve-progress/poll_bonding_curve_progress.py
decode_from_blockSubscribe.py
decode_from_getAccountInfo.py
decode_from_getTransaction.py
listen-migrations/compare_migration_listeners.py
listen-migrations/listen_programsubscribe.py
listen-new-tokens/compare_listeners.py
listen-new-tokens/listen_blocksubscribe.py
listen-new-tokens/listen_geyser.py
listen-new-tokens/listen_logsubscribe.py
listen-new-tokens/listen_logsubscribe_abc.py
Verified live against mainnet — listeners decode tokens including
mayhem-mode and cashback-enabled curves correctly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace idl/pump_fun_idl.json and idl/pump_fees.json with the latest from
pump-fun/pump-public-docs @ 7de0b95 (2026-04-23). pump_swap_idl.json was
already up to date.
Drops the idl/upstream/ vendor copy added in 7864504 in favor of
overwriting in place — the diff lives in git history. README updated to
point at pump-public-docs as the source of truth.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Snapshot of pump-fun/pump-public-docs @ 7de0b95 (2026-04-23) under
idl/upstream/ — pump.json, pump_amm.json, pump_fees.json and their .ts
counterparts. Used for local diffing against the IDLs the bot loads from
idl/; not imported at runtime. README links to the new directory.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>