diff --git a/src/monitoring/universal_block_listener.py b/src/monitoring/universal_block_listener.py index 0403c9d..a538f8f 100644 --- a/src/monitoring/universal_block_listener.py +++ b/src/monitoring/universal_block_listener.py @@ -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 diff --git a/src/platforms/pumpfun/event_parser.py b/src/platforms/pumpfun/event_parser.py index 0753efc..678244e 100644 --- a/src/platforms/pumpfun/event_parser.py +++ b/src/platforms/pumpfun/event_parser.py @@ -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: