Skip to content

Conversation

@smypmsa
Copy link
Member

@smypmsa smypmsa commented Oct 26, 2025

Summary by CodeRabbit

  • New Features

    • Added support for configurable token metadata fields including global and platform configuration pubkeys.
    • Introduced fee vault derivation for creator and platform fee collection.
    • Extended support for multiple token initialization variants.
  • Performance

    • Increased transaction compute unit limits (buy operations from 100,000 to 150,000; sell operations from 60,000 to 150,000).

@smypmsa smypmsa self-assigned this Oct 26, 2025
@smypmsa smypmsa added the bug Something isn't working label Oct 26, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Walkthrough

Added platform-specific configuration support to LetsBonk integration by introducing global_config and platform_config fields to TokenInfo, implementing PDA derivation helpers for fee vaults, enriching pool state decoding, supporting multiple initialize instruction variants, and updating instruction account metadata and compute limits.

Changes

Cohort / File(s) Summary
Core data structure
src/interfaces/core.py
Added global_config and platform_config optional fields to TokenInfo for storing platform configuration references.
PDA derivation helpers
src/platforms/letsbonk/address_provider.py
Introduced derive_creator_fee_vault() and derive_platform_fee_vault() methods to compute program addresses. Extended buy/sell instruction account gathering to include system_program and fee vault accounts, with fallback to constants when token_info lacks config values.
Pool state enrichment
src/platforms/letsbonk/curve_manager.py
Expanded _decode_pool_state_with_idl() to include creator, base_vault, and quote_vault fields extracted from decoded IDL data.
Multiple initialize variants
src/platforms/letsbonk/event_parser.py
Added support for three initialize variants (initialize, initialize_v2, initialize_with_token_2022) by maintaining a list and set of discriminators. Updated token creation parsing to accept any variant, extract global_config and platform_config account keys (indices 2, 3), and populate TokenInfo with these fields.
Instruction account and compute updates
src/platforms/letsbonk/instruction_builder.py
Changed payer account metadata from writable to non-writable in buy/sell paths. Added system_program, platform_fee_vault, and conditional creator_fee_vault to instruction accounts. Increased compute unit limits to 150,000 for both buy and sell operations.

Sequence Diagram

sequenceDiagram
    participant Token Creation Event
    participant Event Parser
    participant Address Provider
    participant Instruction Builder
    
    Token Creation Event->>Event Parser: parse_token_creation_from_instruction()
    activate Event Parser
    Note over Event Parser: Check against 3 initialize variants<br/>(initialize, initialize_v2, initialize_with_token_2022)
    Event Parser->>Event Parser: Extract accounts indices 0-3<br/>(including global_config, platform_config)
    Event Parser->>Event Parser: Construct TokenInfo with config refs
    deactivate Event Parser
    Event Parser-->>Address Provider: TokenInfo with global_config, platform_config
    
    activate Address Provider
    Note over Address Provider: get_buy/sell_instruction_accounts()
    Address Provider->>Address Provider: Use config from TokenInfo<br/>or fallback to constants
    Address Provider->>Address Provider: derive_platform_fee_vault(platform_config)
    Address Provider->>Address Provider: derive_creator_fee_vault(creator, quote_mint)
    deactivate Address Provider
    Address Provider-->>Instruction Builder: Accounts dict with fee vaults
    
    activate Instruction Builder
    Note over Instruction Builder: Build instruction with updated<br/>payer metadata + fee accounts +<br/>150k compute units
    deactivate Instruction Builder
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • event_parser.py: Logic refactoring to support multiple discriminators and account extraction requires careful verification of variant handling and index correctness
  • address_provider.py: New PDA derivation methods and integration with existing account-gathering logic need validation against token_info fallback behavior
  • instruction_builder.py: Account metadata changes (payer writability) and compute limit increases should be verified against LetsBonk program requirements

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 Three paths to initialize, now recognized with glee,
Platform vaults and config keys flow through the PSI,
Fee vaults derive where creators and platforms meet,
More compute cycles granted, the network runs complete,
Configuration spreads its wings across the bonking spree! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Fix/update letsbonk fun instructions in the bot" is partially related to the changeset. It accurately refers to instruction-related updates, which is evident in the instruction_builder.py changes (modified payer writable flags, new accounts, and increased compute unit limits). However, the title does not fully capture the scope of the work, which includes significant infrastructure changes such as new fields in TokenInfo (core.py), new PDA-derivation helper methods (address_provider.py), expanded pool state decoding (curve_manager.py), and support for multiple initialize variants (event_parser.py). While the title reflects a real and substantial aspect of the changeset, it is somewhat overly broad and does not convey the complete nature of the updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/bonkfun-instructions-update

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@smypmsa smypmsa merged commit 68cac87 into main Oct 26, 2025
1 check was pending
@smypmsa smypmsa deleted the feat/bonkfun-instructions-update branch October 26, 2025 15:22
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/platforms/letsbonk/event_parser.py (1)

205-218: Remove overly strict geyser prefilter tied to a single platform_config.

Pools may use different platform_config PDAs. Filtering by the default from get_system_addresses() will drop valid initializes. Rely on program id + discriminator checks instead.

Apply:

-                # Check if it's the LetsBonk platform config account
-                has_platform_config = False
-                for acc_idx in ix.accounts:
-                    if acc_idx < len(msg.account_keys):
-                        acc_key = msg.account_keys[acc_idx]
-                        if bytes(acc_key) == bytes(
-                            self.address_provider.get_system_addresses()[
-                                "platform_config"
-                            ]
-                        ):
-                            has_platform_config = True
-                            break
-
-                if not has_platform_config:
-                    continue
+                # Do not prefilter by a single platform_config; variants exist per pool.
🧹 Nitpick comments (1)
src/platforms/letsbonk/curve_manager.py (1)

189-191: Normalize types for newly exposed fields (creator/base_vault/quote_vault).

Ensure these are consistently typed (Pubkey or base58 string) to avoid downstream surprises. Consider decoding to Pubkey here (and convert to string at the edges), and document the expected types in the docstring.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7377e17 and 9da52a3.

📒 Files selected for processing (5)
  • src/interfaces/core.py (1 hunks)
  • src/platforms/letsbonk/address_provider.py (6 hunks)
  • src/platforms/letsbonk/curve_manager.py (1 hunks)
  • src/platforms/letsbonk/event_parser.py (8 hunks)
  • src/platforms/letsbonk/instruction_builder.py (6 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Enforce max line length of 88 characters in Python (Ruff config)
Use 4 spaces for indentation in Python files
Target Python version 3.11+ features and syntax
Prefer double quotes for strings in Python code
Enable and honor import sorting in Python modules
Apply Ruff rule sets: Security (S), Annotations (ANN), Exceptions (BLE, TRY), Complexity (C90), Pylint conventions (PL), and no commented-out code (ERA)
Order imports as: standard library, third-party, then local imports
Use Google-style docstrings for functions and classes
Provide type hints for all public functions
Use a module-level logger via get_logger(name)
Wrap risky operations in try/except with proper logging
Implement rate limiting and retry mechanisms where external calls are made
Perform comprehensive input validation for externally sourced data

**/*.py: Limit lines to 88 characters
Use 4 spaces for indentation (never tabs)
Use double quotes for strings consistently
Target Python 3.11+ features and syntax
Enable automatic import sorting and organization
Order imports: standard library first, third-party second, local last
Add type hints to all public functions and methods
Use modern typing syntax (e.g., X | Y unions)
Include explicit return type annotations
Use typing.Any for complex/unknown types (from typing import Any)
Use Google-style docstrings for all functions and classes
Wrap external operations (RPC calls, file I/O) in try/except blocks
Log exceptions with context using logging.exception()
Provide meaningful error messages when handling exceptions
Do not suppress exceptions without good reason
Use get_logger(name) with logger from utils.logger
Use appropriate log levels (DEBUG, INFO, WARNING, ERROR) with contextual messages
Never hardcode secrets (private keys, API tokens)
Use environment variables for sensitive configuration
Do not log sensitive information
Validate all external inputs
Comply with Ruff security rules (S)
Comply with Ruff type annotation rules (ANN)
Comply...

Files:

  • src/platforms/letsbonk/curve_manager.py
  • src/platforms/letsbonk/address_provider.py
  • src/platforms/letsbonk/event_parser.py
  • src/interfaces/core.py
  • src/platforms/letsbonk/instruction_builder.py
src/{client,trading,monitoring,platforms}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Separate concerns into client, trading, monitoring, and platforms packages under src/

Files:

  • src/platforms/letsbonk/curve_manager.py
  • src/platforms/letsbonk/address_provider.py
  • src/platforms/letsbonk/event_parser.py
  • src/platforms/letsbonk/instruction_builder.py
src/platforms/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Implement platform-specific logic under src/platforms/

src/platforms/**/*.py: Platform-specific modules may only import from their own package and core/interfaces
platforms/ may depend on core/ and interfaces/ only
Implement platform-specific functionality via factory pattern using interfaces

Update platform-specific implementations under src/platforms/ when adding features

Files:

  • src/platforms/letsbonk/curve_manager.py
  • src/platforms/letsbonk/address_provider.py
  • src/platforms/letsbonk/event_parser.py
  • src/platforms/letsbonk/instruction_builder.py
src/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)

src/**/*.py: Use snake_case for all Python file names
Avoid circular imports between packages
Use asyncio.create_task() for concurrent operations
Implement proper cleanup on shutdown for async tasks/resources

Files:

  • src/platforms/letsbonk/curve_manager.py
  • src/platforms/letsbonk/address_provider.py
  • src/platforms/letsbonk/event_parser.py
  • src/interfaces/core.py
  • src/platforms/letsbonk/instruction_builder.py
src/interfaces/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place abstract base classes in src/interfaces/

interfaces/ defines abstract base classes and protocols

Files:

  • src/interfaces/core.py
🧬 Code graph analysis (2)
src/platforms/letsbonk/address_provider.py (1)
src/core/pubkeys.py (1)
  • SystemAddresses (39-62)
src/platforms/letsbonk/event_parser.py (4)
src/interfaces/core.py (1)
  • get_instruction_discriminators (385-391)
src/platforms/pumpfun/event_parser.py (2)
  • get_instruction_discriminators (386-392)
  • get_account_key (284-290)
src/utils/idl_manager.py (1)
  • get_instruction_discriminators (134-144)
src/utils/idl_parser.py (2)
  • get_instruction_discriminators (67-69)
  • get_account_key (128-133)
🪛 Ruff (0.14.1)
src/platforms/letsbonk/address_provider.py

31-33: Do not perform function call Pubkey.from_string in dataclass defaults

(RUF009)

🔇 Additional comments (7)
src/interfaces/core.py (1)

41-42: LGTM: TokenInfo gains LetsBonk config hooks.

Fields align with platform needs and type hints are correct.

src/platforms/letsbonk/instruction_builder.py (2)

116-116: Confirm payer non-writable is acceptable for buy/sell CPI.

Some programs mark payer writable; here it’s set to non-writable. Please validate against the LetsBonk IDL/accounts spec or a devnet tx to ensure the program doesn’t require payer to be writable.


525-526: CU limit bump to 150k: OK. Ensure CU price is set upstream.

The higher limit makes sense. Verify that the transaction builder also sets a compute unit price (priority fee) and caches blockhashes as per project guidelines.

Also applies to: 539-539

src/platforms/letsbonk/event_parser.py (1)

285-299: LGTM: discriminator set checks across block paths.

Using a set for O(1) membership and validating account/data sizes is solid.

Please sanity-check on a devnet block sample that includes both initialize_v2 and initialize_with_token_2022.

Also applies to: 289-289, 344-345

src/platforms/letsbonk/address_provider.py (3)

31-33: Use a regular class or module-level constants instead of ClassVar in dataclass.

The suggested ClassVar fix masks a structural issue: LetsBonkAddresses is a dataclass with zero instance fields—it's purely a constants container. RUF009 flags function calls in dataclass field defaults; using ClassVar sidesteps the warning but leaves an inappropriate dataclass decorator.

Better solutions:

  1. Remove @dataclass entirely and make it a regular class (cleanest for a constants container)
  2. Move these constants to module level, outside any class

Using ClassVar technically silences RUF009 but leaves the code semantically confused about what the class represents.

Likely an incorrect or invalid review comment.


226-272: Verified: PDA seeds are correct.

Both fee vault PDA seeds match the IDL specification:

  • Creator fee vault: Seeds [creator, quote_mint] confirmed in IDL claim_creator_fee instruction
  • Platform fee vault: Seeds [platform_config, quote_mint] confirmed in IDL claim_platform_fee_from_vault instruction

The implementation correctly derives these PDAs using Pubkey.find_program_address() with the matching seed order. Fee vaults are intentionally passed as remaining accounts beyond the 15 IDL-defined accounts, which is documented in the code and is a valid Solana pattern for optional accounts required by the on-chain program.


299-312: Make user ATA and base_token_program Token‑2022 aware, and surface base_token_program to builder.

For pools initialized with Token‑2022, the ATA derivation and base_token_program must use the Token‑2022 program id; otherwise buys/sells will fail due to wrong accounts.

Apply:

@@ def get_buy_instruction_accounts(...):
-        accounts = {
+        # Determine token program for base mint
+        is_token_2022 = bool(getattr(token_info, "additional_data", None) and token_info.additional_data.get("is_token_2022"))
+        base_token_program = (
+            SystemAddresses.TOKEN_2022_PROGRAM if is_token_2022 else SystemAddresses.TOKEN_PROGRAM
+        )
+        accounts = {
             "payer": user,
             "authority": additional_accounts["authority"],
             "global_config": global_config,
             "platform_config": platform_config,
             "pool_state": additional_accounts["pool_state"],
-            "user_base_token": self.derive_user_token_account(user, token_info.mint),
+            # Program-aware ATA derivation
+            "user_base_token": get_associated_token_address(
+                user, token_info.mint, base_token_program
+            ),
             "base_vault": additional_accounts["base_vault"],
             "quote_vault": additional_accounts["quote_vault"],
             "base_token_mint": token_info.mint,
             "quote_token_mint": SystemAddresses.SOL_MINT,
-            "base_token_program": SystemAddresses.TOKEN_PROGRAM,
+            "base_token_program": base_token_program,
             "quote_token_program": SystemAddresses.TOKEN_PROGRAM,
             "event_authority": additional_accounts["event_authority"],
             "program": LetsBonkAddresses.PROGRAM,
             "system_program": SystemAddresses.SYSTEM_PROGRAM,
             "platform_fee_vault": self.derive_platform_fee_vault(platform_config),
         }
@@ def get_sell_instruction_accounts(...):
-        accounts = {
+        is_token_2022 = bool(getattr(token_info, "additional_data", None) and token_info.additional_data.get("is_token_2022"))
+        base_token_program = (
+            SystemAddresses.TOKEN_2022_PROGRAM if is_token_2022 else SystemAddresses.TOKEN_PROGRAM
+        )
+        accounts = {
             "payer": user,
             "authority": additional_accounts["authority"],
             "global_config": global_config,
             "platform_config": platform_config,
             "pool_state": additional_accounts["pool_state"],
-            "user_base_token": self.derive_user_token_account(user, token_info.mint),
+            "user_base_token": get_associated_token_address(
+                user, token_info.mint, base_token_program
+            ),
             "base_vault": additional_accounts["base_vault"],
             "quote_vault": additional_accounts["quote_vault"],
             "base_token_mint": token_info.mint,
             "quote_token_mint": SystemAddresses.SOL_MINT,
-            "base_token_program": SystemAddresses.TOKEN_PROGRAM,
+            "base_token_program": base_token_program,
             "quote_token_program": SystemAddresses.TOKEN_PROGRAM,
             "event_authority": additional_accounts["event_authority"],
             "program": LetsBonkAddresses.PROGRAM,
             "system_program": SystemAddresses.SYSTEM_PROGRAM,
             "platform_fee_vault": self.derive_platform_fee_vault(platform_config),
         }

Note: Ensure SystemAddresses exposes TOKEN_2022_PROGRAM. If not, add it in src/core/pubkeys.py and re-export via SystemAddresses.

Also applies to: 313-330, 368-385, 387-394

Comment on lines +36 to 53
# Get all initialize instruction discriminators from injected IDL parser
# LetsBonk has multiple initialize variants: initialize, initialize_v2, initialize_with_token_2022
discriminators = self._idl_parser.get_instruction_discriminators()
self._initialize_discriminator_bytes = discriminators["initialize"]
self._initialize_discriminator = struct.unpack(
"<Q", self._initialize_discriminator_bytes
)[0]

logger.info("LetsBonk event parser initialized with injected IDL parser")
self._initialize_discriminator_bytes_list = [
discriminators["initialize"],
discriminators["initialize_v2"],
discriminators["initialize_with_token_2022"],
]
self._initialize_discriminators = {
struct.unpack("<Q", disc_bytes)[0]
for disc_bytes in self._initialize_discriminator_bytes_list
}

logger.info(
f"LetsBonk event parser initialized with {len(self._initialize_discriminators)} "
f"initialize instruction variants"
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Good: supporting multiple initialize variants. Add a Token‑2022 hint for downstream.

Set a flag that indicates when the initialize variant is initialize_with_token_2022 so builders/address providers can choose the correct token program.

Apply:

@@ def parse_token_creation_from_instruction(...):
-            # Accept any of the initialize instruction variants
+            # Accept any of the initialize instruction variants
             if not decoded or decoded["instruction_name"] not in {
                 "initialize",
                 "initialize_v2",
                 "initialize_with_token_2022",
             }:
                 return None
@@
-            return TokenInfo(
+            is_token_2022 = decoded["instruction_name"] == "initialize_with_token_2022"
+            return TokenInfo(
                 name=base_mint_param.get("name", ""),
                 symbol=base_mint_param.get("symbol", ""),
                 uri=base_mint_param.get("uri", ""),
                 mint=base_mint,
                 platform=Platform.LETS_BONK,
                 pool_state=pool_state,
                 base_vault=base_vault,
                 quote_vault=quote_vault,
                 global_config=global_config,
                 platform_config=platform_config,
                 user=creator,
                 creator=creator,
                 creation_timestamp=monotonic(),
+                additional_data={"is_token_2022": is_token_2022},
             )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/platforms/letsbonk/event_parser.py around lines 36 to 53, add a boolean
flag on the parser that records whether the initialize variant include the
initialize_with_token_2022 discriminator so downstream builders/address
providers can pick the correct token program; after you build
self._initialize_discriminator_bytes_list or self._initialize_discriminators set
self._initialize_with_token_2022 = True if
discriminators["initialize_with_token_2022"] (or its unpacked integer) is
present in the list/set, otherwise set it to False, and ensure the logger still
reports the initialized variants (you can include the new flag in the state but
do not change logging semantics unless you want to mention the flag in the
message).

Comment on lines +169 to +193
# Add remaining accounts (required by the program for fee collection)
# These are not explicitly listed in IDL but required by the program
buy_accounts.append(
AccountMeta(
pubkey=accounts_info["system_program"],
is_signer=False,
is_writable=False,
)
) # #16: System Program
buy_accounts.append(
AccountMeta(
pubkey=accounts_info["platform_fee_vault"],
is_signer=False,
is_writable=True,
)
) # #17: Platform fee vault
if "creator_fee_vault" in accounts_info:
buy_accounts.append(
AccountMeta(
pubkey=accounts_info["creator_fee_vault"],
is_signer=False,
is_writable=True,
)
) # #18: Creator fee vault

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Add program-aware Token-2022 handling and include new accounts in “required accounts”.

  • If a pool was initialized via initialize_with_token_2022, you must:

    • Create the user ATA with Token-2022 program id.
    • Pass the Token-2022 program id in base_token_program (and keep SPL Token v1 for WSOL/quote).
      Currently both are hardcoded to SPL Token v1, which will fail for Token-2022 pools.
  • Also, since you now pass system_program, platform_fee_vault, and optionally creator_fee_vault, include them in get_required_accounts_for_buy/sell so your priority fee sizing and access lists remain accurate.

Apply these changes:

@@ def build_buy_instruction(...):
-        # 1. Create idempotent ATA for base token
-        ata_instruction = create_idempotent_associated_token_account(
-            user,  # payer
-            user,  # owner
-            token_info.mint,  # mint
-            SystemAddresses.TOKEN_PROGRAM,  # token program
-        )
+        # 1. Create idempotent ATA for base token (Token-2022 aware)
+        base_token_program = accounts_info.get(
+            "base_token_program", SystemAddresses.TOKEN_PROGRAM
+        )
+        ata_instruction = create_idempotent_associated_token_account(
+            user,  # payer
+            user,  # owner
+            token_info.mint,  # mint
+            base_token_program,  # token program (spl-token or token-2022)
+        )
@@
-            AccountMeta(
-                pubkey=SystemAddresses.TOKEN_PROGRAM, is_signer=False, is_writable=False
-            ),  # base_token_program
+            AccountMeta(
+                pubkey=base_token_program, is_signer=False, is_writable=False
+            ),  # base_token_program (Token-2022 aware)

And mirror the same for the sell path:

@@ def build_sell_instruction(...):
-        # 2. Initialize WSOL account
+        # 2. Initialize WSOL account
         initialize_wsol_ix = self._create_initialize_account_instruction(
             wsol_account, SystemAddresses.SOL_MINT, user
         )
@@
-            AccountMeta(
-                pubkey=SystemAddresses.TOKEN_PROGRAM, is_signer=False, is_writable=False
-            ),  # base_token_program
+            AccountMeta(
+                pubkey=accounts_info.get(
+                    "base_token_program", SystemAddresses.TOKEN_PROGRAM
+                ),
+                is_signer=False,
+                is_writable=False,
+            ),  # base_token_program (Token-2022 aware)

Finally, include the new accounts in the “required accounts” sets:

@@ def get_required_accounts_for_buy(...):
-        return [
+        req = [
             accounts_info["pool_state"],
             accounts_info["user_base_token"],
             accounts_info["base_vault"],
             accounts_info["quote_vault"],
             token_info.mint,
             SystemAddresses.SOL_MINT,
             accounts_info["program"],
-        ]
+        ]
+        # Include fee/system accounts for accurate access set
+        req.append(accounts_info["system_program"])
+        req.append(accounts_info["platform_fee_vault"])
+        if "creator_fee_vault" in accounts_info:
+            req.append(accounts_info["creator_fee_vault"])
+        return req
@@ def get_required_accounts_for_sell(...):
-        return [
+        req = [
             accounts_info["pool_state"],
             accounts_info["user_base_token"],
             accounts_info["base_vault"],
             accounts_info["quote_vault"],
             token_info.mint,
             SystemAddresses.SOL_MINT,
             accounts_info["program"],
-        ]
+        ]
+        req.append(accounts_info["system_program"])
+        req.append(accounts_info["platform_fee_vault"])
+        if "creator_fee_vault" in accounts_info:
+            req.append(accounts_info["creator_fee_vault"])
+        return req


---

🏁 Script executed:

```shell
#!/bin/bash
# Find the instruction_builder.py file
fd -t f "instruction_builder.py" src/

# Get file info and line count
if [ -f "src/platforms/letsbonk/instruction_builder.py" ]; then
  echo "=== File found ==="
  wc -l "src/platforms/letsbonk/instruction_builder.py"
  
  echo -e "\n=== Lines 169-193 (snippet context) ==="
  sed -n '165,200p' "src/platforms/letsbonk/instruction_builder.py"
fi

Length of output: 1603


🏁 Script executed:

#!/bin/bash
# Find build_buy_instruction method
echo "=== build_buy_instruction method ==="
rg -n -A 30 "def build_buy_instruction" src/platforms/letsbonk/instruction_builder.py

echo -e "\n=== build_sell_instruction method ==="
rg -n -A 30 "def build_sell_instruction" src/platforms/letsbonk/instruction_builder.py

Length of output: 2540


🏁 Script executed:

#!/bin/bash
# Find get_required_accounts methods
echo "=== get_required_accounts_for_buy method ==="
rg -n -A 15 "def get_required_accounts_for_buy" src/platforms/letsbonk/instruction_builder.py

echo -e "\n=== get_required_accounts_for_sell method ==="
rg -n -A 15 "def get_required_accounts_for_sell" src/platforms/letsbonk/instruction_builder.py

Length of output: 1396


🏁 Script executed:

#!/bin/bash
# Search for TOKEN_PROGRAM and Token-2022 references
echo "=== TOKEN_PROGRAM hardcoding ==="
rg -n "TOKEN_PROGRAM" src/platforms/letsbonk/instruction_builder.py | head -20

echo -e "\n=== Token-2022 references ==="
rg -n -i "token.?2022\|token_2022" src/platforms/letsbonk/instruction_builder.py

Length of output: 786


🏁 Script executed:

#!/bin/bash
# Check if base_token_program is used in accounts_info
echo "=== base_token_program references ==="
rg -n "base_token_program" src/platforms/letsbonk/instruction_builder.py

Length of output: 119



---

🏁 Script executed:

```shell
#!/bin/bash
# Get full content of get_required_accounts_for_buy and get_required_accounts_for_sell
echo "=== get_required_accounts_for_buy (lines 373-410) ==="
sed -n '373,410p' "src/platforms/letsbonk/instruction_builder.py"

echo -e "\n=== get_required_accounts_for_sell (lines 398-435) ==="
sed -n '398,435p' "src/platforms/letsbonk/instruction_builder.py"

Length of output: 2777


🏁 Script executed:

#!/bin/bash
# Get context around lines 103 and 258 (owner=TOKEN_PROGRAM cases)
echo "=== Context around line 103 (build_buy_instruction ATA) ==="
sed -n '95,110p' "src/platforms/letsbonk/instruction_builder.py"

echo -e "\n=== Context around line 258 (build_sell_instruction WSOL) ==="
sed -n '250,265p' "src/platforms/letsbonk/instruction_builder.py"

Length of output: 1329


🏁 Script executed:

#!/bin/bash
# Search for Token-2022 in entire letsbonk platform
echo "=== Token-2022 in letsbonk platform ==="
rg -i "token.?2022\|token_2022\|initialize_with_token_2022" src/platforms/letsbonk/

echo -e "\n=== Check if base_token_program key is set in address_provider ==="
rg -n "base_token_program" src/platforms/letsbonk/

Length of output: 505


🏁 Script executed:

#!/bin/bash
# Check the address provider methods to see what keys are in accounts_info
echo "=== get_buy_instruction_accounts in address provider ==="
fd -t f "*.py" src/platforms/letsbonk/ -x grep -l "get_buy_instruction_accounts"

echo -e "\n=== get_sell_instruction_accounts in address provider ==="
fd -t f "*.py" src/platforms/letsbonk/ -x grep -l "get_sell_instruction_accounts"

Length of output: 683


🏁 Script executed:

#!/bin/bash
# Get full build_buy_instruction to see if it references base_token_program
echo "=== Full build_buy_instruction method ==="
sed -n '53,215p' "src/platforms/letsbonk/instruction_builder.py"

Length of output: 6426



---

🏁 Script executed:

```shell
#!/bin/bash
# Get full build_sell_instruction to compare
echo "=== Full build_sell_instruction method ==="
sed -n '218,370p' "src/platforms/letsbonk/instruction_builder.py"

Length of output: 6079


🏁 Script executed:

#!/bin/bash
# Check address_provider to see full get_buy/sell_instruction_accounts implementation
echo "=== get_buy_instruction_accounts method ==="
rg -n -A 50 "def get_buy_instruction_accounts" src/platforms/letsbonk/address_provider.py | head -70

echo -e "\n=== get_sell_instruction_accounts method ==="
rg -n -A 50 "def get_sell_instruction_accounts" src/platforms/letsbonk/address_provider.py | head -70

Length of output: 4716


Use dynamic base_token_program from accounts_info instead of hardcoding TOKEN_PROGRAM, and include fee/system accounts in priority fee calculation.

The review identifies three critical issues:

  1. Hardcoded TOKEN_PROGRAM in ATA/account creation: Lines 83 (build_buy) and 258 (build_sell) hardcode SystemAddresses.TOKEN_PROGRAM instead of using accounts_info.get("base_token_program"), which already exists in accounts_info. Token-2022 pools require the Token-2022 program ID here.

  2. Hardcoded token program in AccountMeta: Lines 154–157 (build_buy) and 309–312 (build_sell) also hardcode both base_token_program and quote_token_program instead of reading from accounts_info.

  3. Missing accounts in priority fee calculation: get_required_accounts_for_buy (lines 373–397) and get_required_accounts_for_sell (lines 398–424) return only 7 accounts. They must also include system_program, platform_fee_vault, and optionally creator_fee_vault—these accounts are already passed to the instruction builders and must be included in the required accounts list for accurate priority fee sizing.

Apply the suggested diffs to use accounts_info.get("base_token_program", SystemAddresses.TOKEN_PROGRAM) in lines 83, 154, 157, 258, 309, 312, and extend the return statements in both get_required_accounts_* methods to append the fee/system accounts.

🤖 Prompt for AI Agents
src/platforms/letsbonk/instruction_builder.py around lines 169-193, change
hardcoded TOKEN_PROGRAM usages to read dynamic program IDs from accounts_info
and include fee/system accounts in required-account lists: replace occurrences
where SystemAddresses.TOKEN_PROGRAM is used for base/quote token program with
accounts_info.get("base_token_program", SystemAddresses.TOKEN_PROGRAM) (and
accounts_info.get("quote_token_program", SystemAddresses.TOKEN_PROGRAM) where
appropriate) at the reported sites (build_buy lines ~83,154,157 and build_sell
lines ~258,309,312), use those variables when constructing AccountMeta entries
instead of the hardcoded constant, and update get_required_accounts_for_buy and
get_required_accounts_for_sell to append accounts_info["system_program"],
accounts_info["platform_fee_vault"], and, if present,
accounts_info["creator_fee_vault"] to their returned lists so priority fee
sizing includes system and fee vault accounts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants