Fix buy/sell transactions silently failing on-chain (#157)

* fix(core): disable account_data_size limit and add meta.err checking

The 12.5MB setLoadedAccountsDataSizeLimit was causing all buy transactions
to fail with MaxLoadedAccountsDataSizeExceeded since pump.fun migrated to
Token-2022. Transactions landed on-chain (fees paid) but inner instructions
were rejected — the bot paid gas for nothing.

Changes:
- Disable account_data_size in all bot configs (Token-2022 needs >12.5MB)
- Add meta.err check in get_buy_transaction_details() for clear error
  reporting when transactions fail on-chain
- Include tx signature in platform_aware.py error messages for debugging

Tested: full buy→sell→cleanup cycle works on pump_fun with geyser listener.


* fix(core): check meta.err in confirm_transaction to detect failed txs

Solana transactions can be "confirmed" (included in a block) but still
fail execution if inner program instructions are rejected. Previously,
confirm_transaction only checked that the tx landed on-chain, causing
silent failures in buy, sell, and cleanup operations.

Now fetches the transaction result after confirmation and checks
meta.err, returning False when the transaction failed. This fixes
the ATA cleanup issue where sells were silently failing with
Custom: 6003 errors, leaving non-zero token balances.


* fix(core): treat failed tx fetch as unconfirmed in confirm_transaction

When _get_transaction_result returns None (RPC failure, timeout, etc.),
the function was falling through to return True — silently treating an
unknown state as success. Now returns False with a warning log.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Anton Sauchyk
2026-02-17 10:37:04 +01:00
committed by GitHub
parent c5b0161d05
commit 0b6779ca34
6 changed files with 39 additions and 8 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ compute_units:
# Note: Savings don't show in "consumed CU" but improve tx priority/cost. # Note: Savings don't show in "consumed CU" but improve tx priority/cost.
# Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue. # Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue.
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
account_data_size: 12_500_000 # account_data_size: 12_500_000 # Disabled: causes MaxLoadedAccountsDataSizeExceeded with Token-2022
# Filters for token selection # Filters for token selection
filters: filters:
+1 -1
View File
@@ -63,7 +63,7 @@ compute_units:
# Note: Savings don't show in "consumed CU" but improve tx priority/cost. # Note: Savings don't show in "consumed CU" but improve tx priority/cost.
# Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue. # Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue.
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
account_data_size: 12_500_000 # account_data_size: 12_500_000 # Disabled: causes MaxLoadedAccountsDataSizeExceeded with Token-2022
# Filters for token selection # Filters for token selection
filters: filters:
+1 -1
View File
@@ -63,7 +63,7 @@ compute_units:
# Note: Savings don't show in "consumed CU" but improve tx priority/cost. # Note: Savings don't show in "consumed CU" but improve tx priority/cost.
# Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue. # Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue.
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
account_data_size: 12_500_000 # account_data_size: 12_500_000 # Disabled: causes MaxLoadedAccountsDataSizeExceeded with Token-2022
# Filters for token selection # Filters for token selection
filters: filters:
+1 -1
View File
@@ -61,7 +61,7 @@ compute_units:
# Note: Savings don't show in "consumed CU" but improve tx priority/cost. # Note: Savings don't show in "consumed CU" but improve tx priority/cost.
# Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue. # Note (Nov 23, 2025): with data size set to 512KB, transactions fail - increasing to 12.5MB resolves the issue.
# Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit # Reference: https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
account_data_size: 12_500_000 # account_data_size: 12_500_000 # Disabled: causes MaxLoadedAccountsDataSizeExceeded with Token-2022
# Filters for token selection # Filters for token selection
filters: filters:
+33 -3
View File
@@ -280,14 +280,18 @@ class SolanaClient:
async def confirm_transaction( async def confirm_transaction(
self, signature: str, commitment: str = "confirmed" self, signature: str, commitment: str = "confirmed"
) -> bool: ) -> bool:
"""Wait for transaction confirmation. """Wait for transaction confirmation and verify execution success.
Confirms the transaction landed on-chain, then checks meta.err to
ensure the inner program instructions actually succeeded. A transaction
can be "confirmed" (included in a block) but still fail execution.
Args: Args:
signature: Transaction signature signature: Transaction signature
commitment: Confirmation commitment level commitment: Confirmation commitment level
Returns: Returns:
Whether transaction was confirmed Whether transaction was confirmed AND executed successfully
""" """
await self._rate_limiter.acquire() await self._rate_limiter.acquire()
client = await self.get_client() client = await self.get_client()
@@ -295,11 +299,28 @@ class SolanaClient:
await client.confirm_transaction( await client.confirm_transaction(
signature, commitment=commitment, sleep_seconds=1 signature, commitment=commitment, sleep_seconds=1
) )
return True
except Exception: except Exception:
logger.exception(f"Failed to confirm transaction {signature}") logger.exception(f"Failed to confirm transaction {signature}")
return False return False
# Verify the transaction actually succeeded (no program errors)
result = await self._get_transaction_result(str(signature))
if not result:
logger.warning(
f"Could not fetch transaction {str(signature)[:16]}... "
f"to verify execution — treating as unconfirmed"
)
return False
tx_err = result.get("meta", {}).get("err")
if tx_err:
logger.error(
f"Transaction {str(signature)[:16]}... confirmed but failed: {tx_err}"
)
return False
return True
async def get_transaction_token_balance( async def get_transaction_token_balance(
self, signature: str, user_pubkey: Pubkey, mint: Pubkey self, signature: str, user_pubkey: Pubkey, mint: Pubkey
) -> int | None: ) -> int | None:
@@ -354,6 +375,15 @@ class SolanaClient:
return None, None return None, None
meta = result.get("meta", {}) meta = result.get("meta", {})
# Check for transaction execution errors (e.g., MaxLoadedAccountsDataSizeExceeded)
tx_err = meta.get("err")
if tx_err:
logger.error(
f"Transaction {signature[:16]}... failed with error: {tx_err}"
)
return None, None
mint_str = str(mint) mint_str = str(mint)
# Get tokens received from pre/post token balance diff # Get tokens received from pre/post token balance diff
+2 -1
View File
@@ -156,7 +156,8 @@ class PlatformAwareBuyer(Trader):
else: else:
raise ValueError( raise ValueError(
f"Failed to parse transaction details: tokens={tokens_raw}, " f"Failed to parse transaction details: tokens={tokens_raw}, "
f"sol_spent={sol_spent}" f"sol_spent={sol_spent} (tx: {tx_signature}). "
f"The transaction may have failed on-chain — check explorer."
) )
return TradeResult( return TradeResult(