mirror of
https://github.com/chainstacklabs/pumpfun-bonkfun-bot.git
synced 2026-08-18 01:38:04 +00:00
Fix/update letsbonk fun instructions in the bot (#142)
* feat(core): support multiple initialize instruction variants in LetsBonkEventParser * feat(core): add creator and platform fee vault derivation methods and update account handling in buy/sell instructions * feat(letsbonk): add global_config and platform_config to TokenInfo and update address provider logic
This commit is contained in:
@@ -38,6 +38,8 @@ class TokenInfo:
|
|||||||
pool_state: Pubkey | None = None # LetsBonk specific
|
pool_state: Pubkey | None = None # LetsBonk specific
|
||||||
base_vault: Pubkey | None = None # LetsBonk specific
|
base_vault: Pubkey | None = None # LetsBonk specific
|
||||||
quote_vault: Pubkey | None = None # LetsBonk specific
|
quote_vault: Pubkey | None = None # LetsBonk specific
|
||||||
|
global_config: Pubkey | None = None # LetsBonk specific
|
||||||
|
platform_config: Pubkey | None = None # LetsBonk specific
|
||||||
|
|
||||||
# Common fields
|
# Common fields
|
||||||
user: Pubkey | None = None
|
user: Pubkey | None = None
|
||||||
|
|||||||
@@ -23,11 +23,22 @@ class LetsBonkAddresses:
|
|||||||
PROGRAM: Final[Pubkey] = Pubkey.from_string(
|
PROGRAM: Final[Pubkey] = Pubkey.from_string(
|
||||||
"LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"
|
"LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"
|
||||||
)
|
)
|
||||||
|
# NOTE: GLOBAL_CONFIG is NOT constant across all pools!
|
||||||
|
# Each pool can be initialized with different global_config values. Different global_configs
|
||||||
|
# may define different program-wide settings, versions, or operational parameters.
|
||||||
|
# The correct global_config for each pool is extracted during pool initialization
|
||||||
|
# and stored in TokenInfo.global_config. This value below is a default, used as a fallback.
|
||||||
GLOBAL_CONFIG: Final[Pubkey] = Pubkey.from_string(
|
GLOBAL_CONFIG: Final[Pubkey] = Pubkey.from_string(
|
||||||
"6s1xP3hpbAfFoNtUNF8mfHsjr2Bd97JxFJRWLbL6aHuX"
|
"6s1xP3hpbAfFoNtUNF8mfHsjr2Bd97JxFJRWLbL6aHuX"
|
||||||
)
|
)
|
||||||
|
# NOTE: PLATFORM_CONFIG is NOT constant across all pools!
|
||||||
|
# Each pool is initialized with a specific platform_config that defines its fee structure,
|
||||||
|
# launch restrictions, and other settings. Different pools may use different platform_configs
|
||||||
|
# (e.g., standard launches vs partner launches). The correct platform_config for each pool
|
||||||
|
# is extracted during pool initialization and stored in TokenInfo.platform_config.
|
||||||
|
# This value below is the default/most common platform_config, used as a fallback.
|
||||||
PLATFORM_CONFIG: Final[Pubkey] = Pubkey.from_string(
|
PLATFORM_CONFIG: Final[Pubkey] = Pubkey.from_string(
|
||||||
"FfYek5vEz23cMkWsdJwG2oa6EphsvXSHrGpdALN4g6W1"
|
"5thqcDwKp5QQ8US4XRMoseGeGbmLKMmoKZmS6zHrQAsA"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -212,6 +223,53 @@ class LetsBonkAddressProvider(AddressProvider):
|
|||||||
)
|
)
|
||||||
return event_authority_pda
|
return event_authority_pda
|
||||||
|
|
||||||
|
def derive_creator_fee_vault(
|
||||||
|
self, creator: Pubkey, quote_mint: Pubkey | None = None
|
||||||
|
) -> Pubkey:
|
||||||
|
"""Derive the creator fee vault PDA.
|
||||||
|
|
||||||
|
This vault accumulates creator fees from trades.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
creator: The pool creator's pubkey
|
||||||
|
quote_mint: The quote token mint (defaults to WSOL)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Creator fee vault address
|
||||||
|
"""
|
||||||
|
if quote_mint is None:
|
||||||
|
quote_mint = SystemAddresses.SOL_MINT
|
||||||
|
|
||||||
|
creator_fee_vault, _ = Pubkey.find_program_address(
|
||||||
|
[bytes(creator), bytes(quote_mint)], LetsBonkAddresses.PROGRAM
|
||||||
|
)
|
||||||
|
return creator_fee_vault
|
||||||
|
|
||||||
|
def derive_platform_fee_vault(
|
||||||
|
self, platform_config: Pubkey | None = None, quote_mint: Pubkey | None = None
|
||||||
|
) -> Pubkey:
|
||||||
|
"""Derive the platform fee vault PDA.
|
||||||
|
|
||||||
|
This vault accumulates platform fees from trades.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
platform_config: The platform config account (defaults to LetsBonk config)
|
||||||
|
quote_mint: The quote token mint (defaults to WSOL)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Platform fee vault address
|
||||||
|
"""
|
||||||
|
if platform_config is None:
|
||||||
|
platform_config = LetsBonkAddresses.PLATFORM_CONFIG
|
||||||
|
|
||||||
|
if quote_mint is None:
|
||||||
|
quote_mint = SystemAddresses.SOL_MINT
|
||||||
|
|
||||||
|
platform_fee_vault, _ = Pubkey.find_program_address(
|
||||||
|
[bytes(platform_config), bytes(quote_mint)], LetsBonkAddresses.PROGRAM
|
||||||
|
)
|
||||||
|
return platform_fee_vault
|
||||||
|
|
||||||
def create_wsol_account_with_seed(self, payer: Pubkey, seed: str) -> Pubkey:
|
def create_wsol_account_with_seed(self, payer: Pubkey, seed: str) -> Pubkey:
|
||||||
"""Create a WSOL account address using createAccountWithSeed pattern.
|
"""Create a WSOL account address using createAccountWithSeed pattern.
|
||||||
|
|
||||||
@@ -238,11 +296,25 @@ class LetsBonkAddressProvider(AddressProvider):
|
|||||||
"""
|
"""
|
||||||
additional_accounts = self.get_additional_accounts(token_info)
|
additional_accounts = self.get_additional_accounts(token_info)
|
||||||
|
|
||||||
return {
|
# Use global_config from TokenInfo if available, otherwise use default
|
||||||
|
global_config = (
|
||||||
|
token_info.global_config
|
||||||
|
if token_info.global_config
|
||||||
|
else LetsBonkAddresses.GLOBAL_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use platform_config from TokenInfo if available, otherwise use default
|
||||||
|
platform_config = (
|
||||||
|
token_info.platform_config
|
||||||
|
if token_info.platform_config
|
||||||
|
else LetsBonkAddresses.PLATFORM_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
accounts = {
|
||||||
"payer": user,
|
"payer": user,
|
||||||
"authority": additional_accounts["authority"],
|
"authority": additional_accounts["authority"],
|
||||||
"global_config": LetsBonkAddresses.GLOBAL_CONFIG,
|
"global_config": global_config,
|
||||||
"platform_config": LetsBonkAddresses.PLATFORM_CONFIG,
|
"platform_config": platform_config,
|
||||||
"pool_state": additional_accounts["pool_state"],
|
"pool_state": additional_accounts["pool_state"],
|
||||||
"user_base_token": self.derive_user_token_account(user, token_info.mint),
|
"user_base_token": self.derive_user_token_account(user, token_info.mint),
|
||||||
"base_vault": additional_accounts["base_vault"],
|
"base_vault": additional_accounts["base_vault"],
|
||||||
@@ -253,8 +325,18 @@ class LetsBonkAddressProvider(AddressProvider):
|
|||||||
"quote_token_program": SystemAddresses.TOKEN_PROGRAM,
|
"quote_token_program": SystemAddresses.TOKEN_PROGRAM,
|
||||||
"event_authority": additional_accounts["event_authority"],
|
"event_authority": additional_accounts["event_authority"],
|
||||||
"program": LetsBonkAddresses.PROGRAM,
|
"program": LetsBonkAddresses.PROGRAM,
|
||||||
|
"system_program": SystemAddresses.SYSTEM_PROGRAM,
|
||||||
|
"platform_fee_vault": self.derive_platform_fee_vault(platform_config),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add creator fee vault if creator is known
|
||||||
|
if token_info.creator:
|
||||||
|
accounts["creator_fee_vault"] = self.derive_creator_fee_vault(
|
||||||
|
token_info.creator
|
||||||
|
)
|
||||||
|
|
||||||
|
return accounts
|
||||||
|
|
||||||
def get_sell_instruction_accounts(
|
def get_sell_instruction_accounts(
|
||||||
self, token_info: TokenInfo, user: Pubkey
|
self, token_info: TokenInfo, user: Pubkey
|
||||||
) -> dict[str, Pubkey]:
|
) -> dict[str, Pubkey]:
|
||||||
@@ -269,11 +351,25 @@ class LetsBonkAddressProvider(AddressProvider):
|
|||||||
"""
|
"""
|
||||||
additional_accounts = self.get_additional_accounts(token_info)
|
additional_accounts = self.get_additional_accounts(token_info)
|
||||||
|
|
||||||
return {
|
# Use global_config from TokenInfo if available, otherwise use default
|
||||||
|
global_config = (
|
||||||
|
token_info.global_config
|
||||||
|
if token_info.global_config
|
||||||
|
else LetsBonkAddresses.GLOBAL_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use platform_config from TokenInfo if available, otherwise use default
|
||||||
|
platform_config = (
|
||||||
|
token_info.platform_config
|
||||||
|
if token_info.platform_config
|
||||||
|
else LetsBonkAddresses.PLATFORM_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
accounts = {
|
||||||
"payer": user,
|
"payer": user,
|
||||||
"authority": additional_accounts["authority"],
|
"authority": additional_accounts["authority"],
|
||||||
"global_config": LetsBonkAddresses.GLOBAL_CONFIG,
|
"global_config": global_config,
|
||||||
"platform_config": LetsBonkAddresses.PLATFORM_CONFIG,
|
"platform_config": platform_config,
|
||||||
"pool_state": additional_accounts["pool_state"],
|
"pool_state": additional_accounts["pool_state"],
|
||||||
"user_base_token": self.derive_user_token_account(user, token_info.mint),
|
"user_base_token": self.derive_user_token_account(user, token_info.mint),
|
||||||
"base_vault": additional_accounts["base_vault"],
|
"base_vault": additional_accounts["base_vault"],
|
||||||
@@ -284,8 +380,18 @@ class LetsBonkAddressProvider(AddressProvider):
|
|||||||
"quote_token_program": SystemAddresses.TOKEN_PROGRAM,
|
"quote_token_program": SystemAddresses.TOKEN_PROGRAM,
|
||||||
"event_authority": additional_accounts["event_authority"],
|
"event_authority": additional_accounts["event_authority"],
|
||||||
"program": LetsBonkAddresses.PROGRAM,
|
"program": LetsBonkAddresses.PROGRAM,
|
||||||
|
"system_program": SystemAddresses.SYSTEM_PROGRAM,
|
||||||
|
"platform_fee_vault": self.derive_platform_fee_vault(platform_config),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add creator fee vault if creator is known
|
||||||
|
if token_info.creator:
|
||||||
|
accounts["creator_fee_vault"] = self.derive_creator_fee_vault(
|
||||||
|
token_info.creator
|
||||||
|
)
|
||||||
|
|
||||||
|
return accounts
|
||||||
|
|
||||||
def get_wsol_account_creation_accounts(
|
def get_wsol_account_creation_accounts(
|
||||||
self, user: Pubkey, wsol_account: Pubkey
|
self, user: Pubkey, wsol_account: Pubkey
|
||||||
) -> dict[str, Pubkey]:
|
) -> dict[str, Pubkey]:
|
||||||
|
|||||||
@@ -186,6 +186,9 @@ class LetsBonkCurveManager(CurveManager):
|
|||||||
"real_quote": decoded_pool_state.get("real_quote", 0),
|
"real_quote": decoded_pool_state.get("real_quote", 0),
|
||||||
"status": decoded_pool_state.get("status", 0),
|
"status": decoded_pool_state.get("status", 0),
|
||||||
"supply": decoded_pool_state.get("supply", 0),
|
"supply": decoded_pool_state.get("supply", 0),
|
||||||
|
"creator": decoded_pool_state.get("creator"), # Creator pubkey (as base58 string)
|
||||||
|
"base_vault": decoded_pool_state.get("base_vault"), # Base vault pubkey
|
||||||
|
"quote_vault": decoded_pool_state.get("quote_vault"), # Quote vault pubkey
|
||||||
}
|
}
|
||||||
|
|
||||||
# Calculate additional metrics
|
# Calculate additional metrics
|
||||||
|
|||||||
@@ -33,14 +33,23 @@ class LetsBonkEventParser(EventParser):
|
|||||||
self.address_provider = LetsBonkAddressProvider()
|
self.address_provider = LetsBonkAddressProvider()
|
||||||
self._idl_parser = idl_parser
|
self._idl_parser = idl_parser
|
||||||
|
|
||||||
# Get discriminators from injected IDL parser
|
# 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()
|
discriminators = self._idl_parser.get_instruction_discriminators()
|
||||||
self._initialize_discriminator_bytes = discriminators["initialize"]
|
self._initialize_discriminator_bytes_list = [
|
||||||
self._initialize_discriminator = struct.unpack(
|
discriminators["initialize"],
|
||||||
"<Q", self._initialize_discriminator_bytes
|
discriminators["initialize_v2"],
|
||||||
)[0]
|
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("LetsBonk event parser initialized with injected IDL parser")
|
logger.info(
|
||||||
|
f"LetsBonk event parser initialized with {len(self._initialize_discriminators)} "
|
||||||
|
f"initialize instruction variants"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def platform(self) -> Platform:
|
def platform(self) -> Platform:
|
||||||
@@ -76,7 +85,11 @@ class LetsBonkEventParser(EventParser):
|
|||||||
Returns:
|
Returns:
|
||||||
TokenInfo if token creation found, None otherwise
|
TokenInfo if token creation found, None otherwise
|
||||||
"""
|
"""
|
||||||
if not instruction_data.startswith(self._initialize_discriminator_bytes):
|
# Check if instruction starts with any of the initialize discriminators
|
||||||
|
if not any(
|
||||||
|
instruction_data.startswith(disc_bytes)
|
||||||
|
for disc_bytes in self._initialize_discriminator_bytes_list
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -93,7 +106,12 @@ class LetsBonkEventParser(EventParser):
|
|||||||
decoded = self._idl_parser.decode_instruction(
|
decoded = self._idl_parser.decode_instruction(
|
||||||
instruction_data, account_keys, accounts
|
instruction_data, account_keys, accounts
|
||||||
)
|
)
|
||||||
if not decoded or decoded["instruction_name"] != "initialize":
|
# 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 None
|
||||||
|
|
||||||
args = decoded.get("args", {})
|
args = decoded.get("args", {})
|
||||||
@@ -118,15 +136,18 @@ class LetsBonkEventParser(EventParser):
|
|||||||
# ... other accounts
|
# ... other accounts
|
||||||
|
|
||||||
creator = get_account_key(0) # First signer account (creator)
|
creator = get_account_key(0) # First signer account (creator)
|
||||||
|
global_config = get_account_key(2) # global_config account
|
||||||
|
platform_config = get_account_key(3) # platform_config account
|
||||||
pool_state = get_account_key(5) # pool_state account
|
pool_state = get_account_key(5) # pool_state account
|
||||||
base_mint = get_account_key(6) # base_mint account
|
base_mint = get_account_key(6) # base_mint account
|
||||||
base_vault = get_account_key(8) # base_vault account
|
base_vault = get_account_key(8) # base_vault account
|
||||||
quote_vault = get_account_key(9) # quote_vault account
|
quote_vault = get_account_key(9) # quote_vault account
|
||||||
|
|
||||||
if not all([creator, pool_state, base_mint, base_vault, quote_vault]):
|
if not all([creator, global_config, platform_config, pool_state, base_mint, base_vault, quote_vault]):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Missing required accounts: creator={creator}, pool_state={pool_state}, "
|
f"Missing required accounts: creator={creator}, global_config={global_config}, "
|
||||||
f"base_mint={base_mint}, base_vault={base_vault}, quote_vault={quote_vault}"
|
f"platform_config={platform_config}, pool_state={pool_state}, base_mint={base_mint}, "
|
||||||
|
f"base_vault={base_vault}, quote_vault={quote_vault}"
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -139,6 +160,8 @@ class LetsBonkEventParser(EventParser):
|
|||||||
pool_state=pool_state,
|
pool_state=pool_state,
|
||||||
base_vault=base_vault,
|
base_vault=base_vault,
|
||||||
quote_vault=quote_vault,
|
quote_vault=quote_vault,
|
||||||
|
global_config=global_config,
|
||||||
|
platform_config=platform_config,
|
||||||
user=creator,
|
user=creator,
|
||||||
creator=creator,
|
creator=creator,
|
||||||
creation_timestamp=monotonic(),
|
creation_timestamp=monotonic(),
|
||||||
@@ -219,9 +242,9 @@ class LetsBonkEventParser(EventParser):
|
|||||||
"""Get instruction discriminators for token creation.
|
"""Get instruction discriminators for token creation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of discriminator bytes to match
|
List of discriminator bytes to match (all initialize variants)
|
||||||
"""
|
"""
|
||||||
return [self._initialize_discriminator_bytes]
|
return self._initialize_discriminator_bytes_list
|
||||||
|
|
||||||
def parse_token_creation_from_block(self, block_data: dict) -> TokenInfo | None:
|
def parse_token_creation_from_block(self, block_data: dict) -> TokenInfo | None:
|
||||||
"""Parse token creation from block data (for block listener).
|
"""Parse token creation from block data (for block listener).
|
||||||
@@ -259,11 +282,11 @@ class LetsBonkEventParser(EventParser):
|
|||||||
|
|
||||||
ix_data = bytes(ix.data)
|
ix_data = bytes(ix.data)
|
||||||
|
|
||||||
# Check for initialize discriminator
|
# Check for any initialize discriminator variant
|
||||||
if len(ix_data) >= 8:
|
if len(ix_data) >= 8:
|
||||||
discriminator = struct.unpack("<Q", ix_data[:8])[0]
|
discriminator = struct.unpack("<Q", ix_data[:8])[0]
|
||||||
|
|
||||||
if discriminator == self._initialize_discriminator:
|
if discriminator in self._initialize_discriminators:
|
||||||
# Token creation should have substantial data and many accounts
|
# Token creation should have substantial data and many accounts
|
||||||
if len(ix_data) <= 8 or len(ix.accounts) < 10:
|
if len(ix_data) <= 8 or len(ix.accounts) < 10:
|
||||||
continue
|
continue
|
||||||
@@ -318,7 +341,7 @@ class LetsBonkEventParser(EventParser):
|
|||||||
if len(ix_data) >= 8:
|
if len(ix_data) >= 8:
|
||||||
discriminator = struct.unpack("<Q", ix_data[:8])[0]
|
discriminator = struct.unpack("<Q", ix_data[:8])[0]
|
||||||
|
|
||||||
if discriminator == self._initialize_discriminator:
|
if discriminator in self._initialize_discriminators:
|
||||||
if len(ix_data) <= 8 or len(ix["accounts"]) < 10:
|
if len(ix_data) <= 8 or len(ix["accounts"]) < 10:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@@ -112,9 +112,8 @@ class LetsBonkInstructionBuilder(InstructionBuilder):
|
|||||||
instructions.append(initialize_wsol_ix)
|
instructions.append(initialize_wsol_ix)
|
||||||
|
|
||||||
# 4. Build buy_exact_in instruction with correct account ordering
|
# 4. Build buy_exact_in instruction with correct account ordering
|
||||||
# Based on the IDL and manual examples, the account order should be:
|
|
||||||
buy_accounts = [
|
buy_accounts = [
|
||||||
AccountMeta(pubkey=user, is_signer=True, is_writable=True), # payer
|
AccountMeta(pubkey=user, is_signer=True, is_writable=False), # payer
|
||||||
AccountMeta(
|
AccountMeta(
|
||||||
pubkey=accounts_info["authority"], is_signer=False, is_writable=False
|
pubkey=accounts_info["authority"], is_signer=False, is_writable=False
|
||||||
), # authority
|
), # authority
|
||||||
@@ -167,6 +166,31 @@ class LetsBonkInstructionBuilder(InstructionBuilder):
|
|||||||
), # program
|
), # program
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
# Build instruction data: discriminator + amount_in + minimum_amount_out + share_fee_rate
|
# Build instruction data: discriminator + amount_in + minimum_amount_out + share_fee_rate
|
||||||
SHARE_FEE_RATE = 0 # No sharing fee
|
SHARE_FEE_RATE = 0 # No sharing fee
|
||||||
instruction_data = (
|
instruction_data = (
|
||||||
@@ -244,7 +268,7 @@ class LetsBonkInstructionBuilder(InstructionBuilder):
|
|||||||
|
|
||||||
# 3. Build sell_exact_in instruction with correct account ordering
|
# 3. Build sell_exact_in instruction with correct account ordering
|
||||||
sell_accounts = [
|
sell_accounts = [
|
||||||
AccountMeta(pubkey=user, is_signer=True, is_writable=True), # payer
|
AccountMeta(pubkey=user, is_signer=True, is_writable=False), # payer
|
||||||
AccountMeta(
|
AccountMeta(
|
||||||
pubkey=accounts_info["authority"], is_signer=False, is_writable=False
|
pubkey=accounts_info["authority"], is_signer=False, is_writable=False
|
||||||
), # authority
|
), # authority
|
||||||
@@ -297,6 +321,31 @@ class LetsBonkInstructionBuilder(InstructionBuilder):
|
|||||||
), # program
|
), # program
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Add remaining accounts (required by the program for fee collection)
|
||||||
|
# These are not explicitly listed in IDL but required by the program
|
||||||
|
sell_accounts.append(
|
||||||
|
AccountMeta(
|
||||||
|
pubkey=accounts_info["system_program"],
|
||||||
|
is_signer=False,
|
||||||
|
is_writable=False,
|
||||||
|
)
|
||||||
|
) # #16: System Program
|
||||||
|
sell_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:
|
||||||
|
sell_accounts.append(
|
||||||
|
AccountMeta(
|
||||||
|
pubkey=accounts_info["creator_fee_vault"],
|
||||||
|
is_signer=False,
|
||||||
|
is_writable=True,
|
||||||
|
)
|
||||||
|
) # #18: Creator fee vault
|
||||||
|
|
||||||
# Build instruction data: discriminator + amount_in + minimum_amount_out + share_fee_rate
|
# Build instruction data: discriminator + amount_in + minimum_amount_out + share_fee_rate
|
||||||
SHARE_FEE_RATE = 0 # No sharing fee
|
SHARE_FEE_RATE = 0 # No sharing fee
|
||||||
instruction_data = (
|
instruction_data = (
|
||||||
@@ -473,7 +522,7 @@ class LetsBonkInstructionBuilder(InstructionBuilder):
|
|||||||
if config_override is not None:
|
if config_override is not None:
|
||||||
return config_override
|
return config_override
|
||||||
# Buy operations: ATA creation + WSOL creation/init/close + buy instruction
|
# Buy operations: ATA creation + WSOL creation/init/close + buy instruction
|
||||||
return 100_000
|
return 150_000
|
||||||
|
|
||||||
def get_sell_compute_unit_limit(self, config_override: int | None = None) -> int:
|
def get_sell_compute_unit_limit(self, config_override: int | None = None) -> int:
|
||||||
"""Get the recommended compute unit limit for LetsBonk sell operations.
|
"""Get the recommended compute unit limit for LetsBonk sell operations.
|
||||||
@@ -487,4 +536,4 @@ class LetsBonkInstructionBuilder(InstructionBuilder):
|
|||||||
if config_override is not None:
|
if config_override is not None:
|
||||||
return config_override
|
return config_override
|
||||||
# Sell operations: WSOL creation/init/close + sell instruction
|
# Sell operations: WSOL creation/init/close + sell instruction
|
||||||
return 60_000
|
return 150_000
|
||||||
|
|||||||
Reference in New Issue
Block a user