Add support for Pump Fun creator fee upgrade#98
Conversation
WalkthroughThe changes introduce a new "creator" public key field throughout the token creation, monitoring, and trading pipeline. This includes updating data structures, parsing, event processors, and transaction builders to handle the new creator and its associated "creator vault" address. Configuration files and test outputs are also updated for clarity and consistency. Changes
Sequence Diagram(s)sequenceDiagram
participant Creator
participant EventProcessor
participant TokenInfo
participant Buyer/Seller
Creator->>EventProcessor: Create Token (includes creator pubkey)
EventProcessor->>TokenInfo: Parse and store creator & creator_vault
Buyer/Seller->>TokenInfo: Access creator_vault for transactions
Buyer/Seller->>EventProcessor: Use creator_vault in buy/sell instructions
Poem
Tip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
src/monitoring/block_event_processor.py (1)
46-58:⚠️ Potential issueFallback IDL is now out of sync – missing
creatorargumentIf the on-disk IDL fails to load, the hard-coded fallback only defines three args.
_decode_create_instruction()expects acreatorarg (parsed aspubkey).
With the current code, offsets will be off by 32 bytes, producing corrupted data or raising an exception."args": [ {"name": "name", "type": "string"}, {"name": "symbol", "type": "string"}, {"name": "uri", "type": "string"}, + {"name": "creator", "type": "pubkey"}, ],🧰 Tools
🪛 Ruff (0.8.2)
46-46: Use
logging.exceptioninstead oflogging.errorReplace with
exception(TRY400)
🧹 Nitpick comments (16)
src/trading/seller.py (2)
131-131: Consider usinglogging.exceptionfor better error traceability.While changing to
{e!s}fromstr(e)is good, usinglogger.exceptionwould automatically include the full exception traceback, providing more debugging context.- logger.error(f"Sell operation failed: {e!s}") + logger.exception("Sell operation failed")🧰 Tools
🪛 Ruff (0.8.2)
131-131: Use
logging.exceptioninstead oflogging.errorReplace with
exception(TRY400)
210-210: Consider usinglogging.exceptionfor better error traceability.Similar to the earlier logging change, using
logger.exceptionwould provide more comprehensive error information including the stack trace.- logger.error(f"Sell transaction failed: {e!s}") + logger.exception("Sell transaction failed")🧰 Tools
🪛 Ruff (0.8.2)
210-210: Use
logging.exceptioninstead oflogging.errorReplace with
exception(TRY400)
src/trading/base.py (1)
46-47: Dictionary key naming inconsistency.The
creator_vaultfield is parsed from a snake_case key"creator_vault", but in theto_dictmethod (line 65), it's serialized to a camelCase key"creatorVault". Consider using consistent naming.- creator_vault=Pubkey.from_string(data["creator_vault"]), + creator_vault=Pubkey.from_string(data["creatorVault"]),learning-examples/listen-new-tokens/listen_geyser.py (1)
80-85: Add return type annotation to theread_pubkeyfunction.For consistency with coding standards, add a return type annotation to make the function's purpose clearer.
- def read_pubkey(): + def read_pubkey() -> str:🧰 Tools
🪛 Ruff (0.8.2)
80-80: Missing return type annotation for private function
read_pubkey(ANN202)
src/monitoring/logs_event_processor.py (2)
64-66: Duplicate vault-derivation could be consolidatedThe same
creator→creator_vaultderivation logic now exists in three processors. Re-implementing the PDA calculation in every class introduces repetition and raises the risk of silent divergence if Pump’s seed or program ID ever changes.Consider extracting
_find_creator_vault()into a shared utility (e.g.core/pump_utils.py) or a mix-in so all processors call a single authoritative implementation.
158-175: Utility method can be@staticmethod
_find_creator_vault()does not rely on any instance state; marking it@staticmethodcommunicates that fact and avoids the accidental use ofselfin the future.- def _find_creator_vault(self, creator: Pubkey) -> Pubkey: + @staticmethod + def _find_creator_vault(creator: Pubkey) -> Pubkey:src/monitoring/geyser_event_processor.py (3)
60-65: Add a return-type annotation to satisfy Ruff / readersThe helper already returns a
Pubkey; adding the annotation removes the Ruff warning and improves readability.- def read_pubkey(): + def read_pubkey() -> Pubkey:🧰 Tools
🪛 Ruff (0.8.2)
60-60: Missing return type annotation for private function
read_pubkey(ANN202)
103-105: Broader exception capture & logging styleCatching bare
Exceptionsuppresses vital context and hampers troubleshooting.
Additionally, Ruff (TRY400) recommendslogger.exception, which automatically includes the traceback.- except Exception as e: - logger.error(f"Failed to process transaction data: {e}") + except Exception: + logger.exception("Failed to process transaction data")🧰 Tools
🪛 Ruff (0.8.2)
103-103: Do not catch blind exception:
Exception(BLE001)
104-104: Use
logging.exceptioninstead oflogging.errorReplace with
exception(TRY400)
107-124: Consider factoring out duplicate vault logicIdentical
_find_creator_vault()implementations are present in three processors. Moving this to a shared helper avoids duplication and guarantees uniform PDA derivation.src/monitoring/block_event_processor.py (3)
46-46: Preferlogger.exceptionfor tracebacks- logger.error(f"Failed to load IDL: {e!s}") + logger.exception("Failed to load IDL")🧰 Tools
🪛 Ruff (0.8.2)
46-46: Use
logging.exceptioninstead oflogging.errorReplace with
exception(TRY400)
133-135: Same logging issue on transaction parsing- except Exception as e: - logger.error(f"Error processing transaction: {e!s}") + except Exception: + logger.exception("Error processing transaction")🧰 Tools
🪛 Ruff (0.8.2)
133-133: Do not catch blind exception:
Exception(BLE001)
134-134: Use
logging.exceptioninstead oflogging.errorReplace with
exception(TRY400)
176-193: Repeated vault helper – candidate for shared utilityAll three processors include identical logic. A single shared helper (or even a constant
CREATOR_VAULT_SEED = b"creator-vault") would reduce duplication.Also this method can be
@staticmethod.bots/bot-sniper-3-blocks.yaml (4)
5-10: Alignnamefield with configuration filename.
Thenameis set to"bot-sniper-2"but this file isbot-sniper-3-blocks.yaml. For clarity in logs and monitoring, update the bot name to match.- name: "bot-sniper-2" + name: "bot-sniper-3-blocks"
36-42: Nit: fix typo in priority fee comment.
Correct “riority fee” → “priority fee” for readability.- extra_percentage: 0.0 # Percentage increase on riority fee regardless of the calculation method (0.1 = 10%) + extra_percentage: 0.0 # Percentage increase on priority fee regardless of the calculation method (0.1 = 10%)
53-57: Consider exponential backoff for retries.
Static wait times may be susceptible to rate limits or transient RPC hiccups. An optional exponential backoff strategy could improve reliability.
71-73: Stubbed node provider limits: implement or remove.
Thenode.max_rpssetting is documented but not yet enforced in code. Either implement rate limiting or mark this section as “TODO” for future work.Would you like help adding a simple token bucket rate limiter around RPC calls?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
bots/bot-sniper-2-logs.yaml(1 hunks)bots/bot-sniper-3-blocks.yaml(1 hunks)learning-examples/listen-new-tokens/listen_blocksubscribe.py(2 hunks)learning-examples/listen-new-tokens/listen_geyser.py(2 hunks)learning-examples/listen-new-tokens/listen_logsubscribe+abc.py(1 hunks)learning-examples/listen-new-tokens/listen_logsubscribe.py(1 hunks)src/core/curve.py(4 hunks)src/monitoring/block_event_processor.py(6 hunks)src/monitoring/geyser_event_processor.py(4 hunks)src/monitoring/logs_event_processor.py(5 hunks)src/trading/base.py(3 hunks)src/trading/buyer.py(1 hunks)src/trading/seller.py(3 hunks)tests/test_block_listener.py(1 hunks)tests/test_geyser_listener.py(1 hunks)tests/test_logs_listener.py(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
learning-examples/listen-new-tokens/listen_geyser.py (1)
src/monitoring/geyser_event_processor.py (2)
read_pubkey(60-64)read_string(50-58)
src/monitoring/logs_event_processor.py (3)
src/core/pubkeys.py (2)
PumpAddresses(34-51)SystemAddresses(15-30)src/monitoring/block_event_processor.py (1)
_find_creator_vault(176-193)src/monitoring/geyser_event_processor.py (1)
_find_creator_vault(107-124)
src/monitoring/geyser_event_processor.py (4)
src/core/pubkeys.py (1)
PumpAddresses(34-51)learning-examples/listen-new-tokens/listen_geyser.py (1)
read_pubkey(80-84)src/monitoring/block_event_processor.py (1)
_find_creator_vault(176-193)src/monitoring/logs_event_processor.py (1)
_find_creator_vault(158-175)
🪛 Ruff (0.8.2)
learning-examples/listen-new-tokens/listen_geyser.py
80-80: Missing return type annotation for private function read_pubkey
(ANN202)
src/trading/seller.py
131-131: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
210-210: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
src/monitoring/geyser_event_processor.py
60-60: Missing return type annotation for private function read_pubkey
(ANN202)
103-103: Do not catch blind exception: Exception
(BLE001)
104-104: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
src/monitoring/block_event_processor.py
46-46: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
133-133: Do not catch blind exception: Exception
(BLE001)
134-134: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
src/core/curve.py
111-111: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
112-112: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
112-112: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (24)
bots/bot-sniper-2-logs.yaml (1)
11-11: Configuration change verifiedThe bot is now disabled by setting
enabled: false. This seems intentional as part of the changes supporting the creator fee upgrade, where you might be shifting to a different configuration approach.tests/test_block_listener.py (1)
42-43: Better separation of User and Creator fieldsThe output has been updated to clearly distinguish between the user and creator, which aligns well with the Pump Fun creator fee upgrade. This improves clarity in test outputs and ensures both fields are properly displayed.
learning-examples/listen-new-tokens/listen_blocksubscribe.py (2)
14-14: Added missing dependencyAdding the base58 import to support the new encoding format for public keys.
41-43: Update to standardized public key handlingChanged the type check from "publicKey" to "pubkey" and switched from base64 to base58 encoding, which standardizes public key handling across the codebase to support the creator field.
learning-examples/listen-new-tokens/listen_logsubscribe+abc.py (2)
57-57: Added Creator field to parsingAdded the "creator" field to the list of parsed fields, which is essential for supporting the Pump Fun creator fee upgrade. This change allows the system to extract the creator's public key from token creation instructions.
50-58:Details
✅ Verification successful
Verify Creator field is used in JSON output
The creator field is now parsed correctly, but I notice the code that prints the parsed data (around line 130-132) just iterates through the parsed fields without explicitly mentioning the creator field. This will work as-is since it's included in
parsed_data, but consider adding specific handling if needed.
🏁 Script executed:
#!/bin/bash # Check if there's any specific handling for the creator field elsewhere in the codebase rg -A 5 "creator.*publicKey" --type py learning-examples/Length of output: 1632
🏁 Script executed:
#!/bin/bash # Locate and display how parsed_data is printed to verify handling of the creator field rg -n "parsed_data" -A5 learning-examples/listen-new-tokens/listen_logsubscribe+abc.pyLength of output: 1978
Creator field is correctly included via dynamic iteration
The
for key, value in parsed_data.items():loop at lines 130–132 will print every entry inparsed_data, including"creator", so no additional code is required to surface that field.tests/test_geyser_listener.py (1)
42-43: Improved clarity of token creator information displayThe update correctly distinguishes between the token's user and creator in the output, which aligns with the wider changes for supporting the Pump Fun creator fee upgrade. This change enhances clarity by separately displaying these two distinct roles.
tests/test_logs_listener.py (1)
42-43: Improved clarity of token creator information displayThe update correctly distinguishes between the token's user and creator in the output, which aligns with the broader changes for supporting the Pump Fun creator fee upgrade. This change ensures consistent representation of these distinct roles across the codebase.
src/trading/buyer.py (1)
179-180:Details
✅ Verification successful
Updated transaction account structure to support creator fees
The transaction now properly includes the creator's vault account as writable, which is essential for supporting the new creator fee structure. This change aligns with the Pump Fun upgrade requirements and ensures fees can be directed to the token creator.
🏁 Script executed:
#!/bin/bash # Check if the seller.py file has a similar update for consistency rg -A 3 -B 3 "creator_vault" src/trading/seller.pyLength of output: 386
Consistent creator_vault writable flag
Bothsrc/trading/buyer.py(lines 179–180) andsrc/trading/seller.pynow mark the creator’s vault (token_info.creator_vault) asis_writable=True. This update fully supports the new creator fee structure, aligns with the Pump Fun upgrade requirements, and ensures fees are correctly directed to the token creator.src/trading/seller.py (1)
178-179: Important account change for creator fee support.The transaction now includes the creator's vault account as a writable account, replacing the previous reference to the associated token program. This is a critical change to support the new creator fee structure in the Pump Fun bonding curve.
src/trading/base.py (2)
25-26: Added essential creator fields to support creator fee upgrade.The TokenInfo dataclass now includes two new fields to track the creator's public key and their vault address, which are core components for implementing the creator fee upgrade.
64-65: Serialization of new creator fields.The implementation correctly converts the new Pubkey objects to strings for serialization. The camelCase style for JSON is consistent with other fields like "bondingCurve".
learning-examples/listen-new-tokens/listen_geyser.py (3)
89-89: Added creator public key extraction.The code now extracts the creator public key from the instruction data, which is essential for the creator fee upgrade support.
95-95: Include creator in token info dictionary.This change ensures the creator public key is stored in the token information dictionary, making it available for display and further processing.
116-116: Display creator information in output.This enhances the output to show the creator's public key, which is valuable for debugging and monitoring the creator fee functionality.
src/core/curve.py (3)
8-8: Added Bytes import for creator field.The import now includes the
Bytestype fromconstruct, which is necessary to define the new creator field in the struct.
31-31: Added creator field to bonding curve structure.The bonding curve state now includes a 32-byte field for the creator's public key, which is essential for implementing the creator fee functionality.
48-51: Convert raw creator bytes to Pubkey object.Added code to convert the raw creator bytes to a proper Pubkey object, with appropriate type checking for data safety.
src/monitoring/block_event_processor.py (1)
113-118: Unchecked key access may raiseKeyError
decoded_args["creator"]presumes the key exists. After fixing the fallback IDL this is fine, but you might still defensive-code:creator_str = decoded_args.get("creator") if not creator_str: logger.warning("Creator field missing in decoded args") return None creator = Pubkey.from_string(creator_str)bots/bot-sniper-3-blocks.yaml (5)
1-4: Looks good: header documentation is clear.
The top comments provide useful guidance on customizing the bot parameters.
15-18: Verify supported Geyserauth_typevalues.
You’ve documentedauth_typecan be"basic"or"x-token". Ensure the code parsing this config indeed accepts both values and fails fast on invalid options.
22-26: Clarify sell parameters or document default behavior.
You configurebuy_amountandsell_slippagebut no explicitsell_amount. If the bot sells a fixed or full position, document that in comments; otherwise, consider adding asell_amountfield for symmetry.
27-31: EXTREME FAST mode settings look solid.
The flags and token‐amount overrides are well documented and correctly scoped.
60-68: Cleanup configuration is comprehensive.
The modes and flags cover the main use cases. No immediate changes needed here.
| ("creator", "publicKey"), | ||
| ] |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Added support for parsing the creator public key
The parser now correctly extracts the creator's public key from token creation instructions, which is an essential part of supporting the Pump Fun creator fee upgrade. This change ensures that creator information is properly captured during token monitoring.
🏁 Script executed:
#!/bin/bash
# Check if other listening examples have been similarly updated
fd -e py listen_ learning-examples/listen-new-tokens/ | xargs rg -l "creator.*publicKey"Length of output: 212
🏁 Script executed:
#!/bin/bash
# Find all Python listening example scripts across the repository
fd -e py listen_Length of output: 506
🏁 Script executed:
#!/bin/bash
# Verify if any listening example scripts outside the new-tokens directory reference creator publicKey
fd -e py listen_ | xargs rg -l "creator.*publicKey"Length of output: 234
Ensure Migration Example Parses Creator Public Key
The migration script learning-examples/listen-migrations/listen_logsubscribe.py still references the creator’s public key but doesn’t extract it. To keep all examples in sync and fully support the Pump Fun creator fee upgrade, please add the same parsing logic you introduced in the new-tokens listener.
• learning-examples/listen-migrations/listen_logsubscribe.py: implement extraction of creator.publicKey from token creation instructions, matching the approach in listen-new-tokens/listen_logsubscribe.py.
| logger.error(f"Failed to get curve state: {e!s}") | ||
| raise ValueError(f"Invalid curve state: {e!s}") |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve exception handling.
Consider the following improvements to exception handling:
- Use
logger.exceptionto automatically include traceback - Use
raise ... from eto properly chain exceptions - Keep error messages concise in the exception constructor
- logger.error(f"Failed to get curve state: {e!s}")
- raise ValueError(f"Invalid curve state: {e!s}")
+ logger.exception("Failed to get curve state")
+ raise ValueError("Invalid curve state") from e📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| logger.error(f"Failed to get curve state: {e!s}") | |
| raise ValueError(f"Invalid curve state: {e!s}") | |
| logger.exception("Failed to get curve state") | |
| raise ValueError("Invalid curve state") from e |
🧰 Tools
🪛 Ruff (0.8.2)
111-111: Use logging.exception instead of logging.error
Replace with exception
(TRY400)
112-112: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling
(B904)
112-112: Avoid specifying long messages outside the exception class
(TRY003)
| # Filters for token selection | ||
| filters: | ||
| match_string: null # Only process tokens with this string in name/symbol | ||
| bro_address: null # Only trade tokens created by this user address | ||
| listener_type: "blocks" # Method for detecting new tokens: "logs", "blocks", or "geyser" | ||
| max_token_age: 0.001 # Maximum token age in seconds for processing | ||
| marry_mode: false # Only buy tokens, skip selling | ||
| yolo_mode: false # Continuously trade tokens | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Rename bro_address filter to creator_address.
The new schema introduces a “creator” field; using bro_address here is inconsistent and may confuse users.
-filters:
- match_string: null # Only process tokens with this string in name/symbol
- bro_address: null # Only trade tokens created by this user address
+filters:
+ match_string: null # Only process tokens whose name/symbol contains this string
+ creator_address: null # Only trade tokens created by this public keyAlso update any downstream code or docs that reference bro_address.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Filters for token selection | |
| filters: | |
| match_string: null # Only process tokens with this string in name/symbol | |
| bro_address: null # Only trade tokens created by this user address | |
| listener_type: "blocks" # Method for detecting new tokens: "logs", "blocks", or "geyser" | |
| max_token_age: 0.001 # Maximum token age in seconds for processing | |
| marry_mode: false # Only buy tokens, skip selling | |
| yolo_mode: false # Continuously trade tokens | |
| # Filters for token selection | |
| filters: | |
| match_string: null # Only process tokens whose name/symbol contains this string | |
| creator_address: null # Only trade tokens created by this public key | |
| listener_type: "blocks" # Method for detecting new tokens: "logs", "blocks", or "geyser" | |
| max_token_age: 0.001 # Maximum token age in seconds for processing | |
| marry_mode: false # Only buy tokens, skip selling | |
| yolo_mode: false # Continuously trade tokens |
Recently, the Pump Fun program has been upgraded. The upgrade introduced creator fee. More on that here:
https://github.com/pump-fun/pump-public-docs/blob/main/docs/PUMP_CREATOR_FEE_README.md
The bot has been update to support updated structure of bonding curve and buy/sell transactions on bonding curve. The same changes have been made to the listener in the learning examples (updates for other scripts will come soon).
IDLs in the project have been updated too.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Tests