fix(blocks-listener): skip failed txs + use CreateEvent log for canonical creator

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>
This commit is contained in:
Anton Sauchyk
2026-04-28 18:44:42 +02:00
parent cc85daaeb3
commit d0dea6d4ac
2 changed files with 22 additions and 0 deletions
@@ -258,6 +258,12 @@ class UniversalBlockListener(BaseTokenListener):
if not isinstance(tx, dict) or "transaction" not in tx:
continue
# Skip failed txs — sniping a failed create yields a non-existent
# mint and the buy-side tx then fails with InvalidMint.
meta = tx.get("meta")
if isinstance(meta, dict) and meta.get("err") is not None:
continue
tx_data = tx["transaction"]
# Handle base64 encoded transaction data
+16
View File
@@ -477,6 +477,22 @@ class PumpFunEventParser(EventParser):
if not isinstance(tx, dict) or "transaction" not in tx:
continue
# Prefer parsing the CreateEvent from logs — args.creator on the
# ix is user-supplied and post-2026-04-28 may differ from the
# canonical BC.creator (which the program writes as a PFEE PDA
# in some cases). The CreateEvent log carries the canonical
# creator, so creator_vault derived from it matches the program
# constraint.
meta = tx.get("meta")
if isinstance(meta, dict):
logs = meta.get("logMessages") or meta.get("log_messages")
if logs:
token_info = self.parse_token_creation_from_logs(
logs, signature=""
)
if token_info:
return token_info
# Decode base64 transaction data if needed
tx_data = tx["transaction"]
if isinstance(tx_data, list) and len(tx_data) > 0: