mirror of
https://github.com/chainstacklabs/pumpfun-bonkfun-bot.git
synced 2026-07-27 15:27:44 +00:00
perf(extreme-fast-mode): use processed commitment + tight retry for BC refresh
Before: BC fetch in extreme_fast_mode used default (confirmed) commitment and retried up to 10 times with growing backoff (~10s total). Geyser/logs fire on processed, so the BC isn't yet at confirmed commitment when the bot reads it — most fetches failed and burned the full retry budget, adding ~10s to detect→confirmed. After: read at processed commitment to match the listener event horizon, and cap retries at 4 with 150ms gaps (~600ms ceiling). Most reads succeed on the first attempt. Mainnet benchmark (n=4 successful buys, geyser listener): buy_slot − create_slot: min=2 median=3 max=9 (~0.8s — 3.6s on chain) wall detect→confirmed: median 2-3s (1s resolution) Best case 2 slots = next slot after creation + tx propagation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-4
@@ -147,11 +147,15 @@ class SolanaClient:
|
|||||||
return result["result"]
|
return result["result"]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_account_info(self, pubkey: Pubkey) -> dict[str, Any]:
|
async def get_account_info(
|
||||||
|
self, pubkey: Pubkey, commitment: str | None = None
|
||||||
|
) -> dict[str, Any]:
|
||||||
"""Get account info from the blockchain.
|
"""Get account info from the blockchain.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
pubkey: Public key of the account
|
pubkey: Public key of the account
|
||||||
|
commitment: Optional commitment override (e.g., "processed" for
|
||||||
|
fresh state right after a geyser event; default "confirmed")
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Account info response
|
Account info response
|
||||||
@@ -161,9 +165,10 @@ class SolanaClient:
|
|||||||
"""
|
"""
|
||||||
await self._rate_limiter.acquire()
|
await self._rate_limiter.acquire()
|
||||||
client = await self.get_client()
|
client = await self.get_client()
|
||||||
response = await client.get_account_info(
|
kwargs: dict[str, Any] = {"encoding": "base64"}
|
||||||
pubkey, encoding="base64"
|
if commitment is not None:
|
||||||
) # base64 encoding for account data by default
|
kwargs["commitment"] = commitment
|
||||||
|
response = await client.get_account_info(pubkey, **kwargs)
|
||||||
if not response.value:
|
if not response.value:
|
||||||
raise ValueError(f"Account {pubkey} not found")
|
raise ValueError(f"Account {pubkey} not found")
|
||||||
return response.value
|
return response.value
|
||||||
|
|||||||
@@ -38,17 +38,24 @@ class PumpFunCurveManager(CurveManager):
|
|||||||
"""Get the platform this manager serves."""
|
"""Get the platform this manager serves."""
|
||||||
return Platform.PUMP_FUN
|
return Platform.PUMP_FUN
|
||||||
|
|
||||||
async def get_pool_state(self, pool_address: Pubkey) -> dict[str, Any]:
|
async def get_pool_state(
|
||||||
|
self, pool_address: Pubkey, commitment: str | None = None
|
||||||
|
) -> dict[str, Any]:
|
||||||
"""Get the current state of a pump.fun bonding curve.
|
"""Get the current state of a pump.fun bonding curve.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
pool_address: Address of the bonding curve
|
pool_address: Address of the bonding curve
|
||||||
|
commitment: Optional commitment override. Pass "processed" right
|
||||||
|
after a geyser/logs event so the BC is readable in the same
|
||||||
|
slot it was created (default: confirmed, ~1-2 slot lag).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dictionary containing bonding curve state data
|
Dictionary containing bonding curve state data
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
account = await self.client.get_account_info(pool_address)
|
account = await self.client.get_account_info(
|
||||||
|
pool_address, commitment=commitment
|
||||||
|
)
|
||||||
if not account.data:
|
if not account.data:
|
||||||
raise ValueError(f"No data in bonding curve account {pool_address}")
|
raise ValueError(f"No data in bonding curve account {pool_address}")
|
||||||
|
|
||||||
|
|||||||
@@ -76,18 +76,19 @@ class PlatformAwareBuyer(Trader):
|
|||||||
)
|
)
|
||||||
pool_state = None
|
pool_state = None
|
||||||
last_err: Exception | None = None
|
last_err: Exception | None = None
|
||||||
# Up to ~6s of retries — pumpportal frequently fires before
|
# Use processed commitment — geyser/logs fire on processed
|
||||||
# the BC account is RPC-readable. Without a settled BC the
|
# so the BC is typically readable in the same slot. Most
|
||||||
# bot can't pick the right fee_recipient or creator_vault.
|
# listeners only need 1 attempt; pumpportal occasionally
|
||||||
for attempt in range(10):
|
# races the on-chain commit, so allow a few quick retries.
|
||||||
|
for attempt in range(4):
|
||||||
try:
|
try:
|
||||||
pool_state = await curve_manager.get_pool_state(
|
pool_state = await curve_manager.get_pool_state(
|
||||||
pool_address
|
pool_address, commitment="processed"
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
except Exception as inner: # noqa: BLE001
|
except Exception as inner: # noqa: BLE001
|
||||||
last_err = inner
|
last_err = inner
|
||||||
await asyncio.sleep(min(0.3 + 0.3 * attempt, 1.5))
|
await asyncio.sleep(0.15)
|
||||||
if pool_state is None:
|
if pool_state is None:
|
||||||
raise last_err or RuntimeError(
|
raise last_err or RuntimeError(
|
||||||
"pool_state unavailable after retries"
|
"pool_state unavailable after retries"
|
||||||
|
|||||||
Reference in New Issue
Block a user