minor fixes

This commit is contained in:
smypmsa
2025-03-06 13:52:40 +00:00
parent 4f800bbbbe
commit 25c304f0fe
5 changed files with 65 additions and 40 deletions
+18 -2
View File
@@ -72,10 +72,19 @@ async def main() -> None:
args = parse_args() args = parse_args()
# Get configuration values, preferring command line args over config.py # Get configuration values, preferring command line args over config.py
rpc_endpoint: str | None = args.rpc or os.environ.get("SOLANA_NODE_RPC_ENDPOINT") rpc_endpoint: str | None = (
wss_endpoint: str | None = args.wss or os.environ.get("SOLANA_NODE_WSS_ENDPOINT") args.rpc
or os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
or config.PUBLIC_RPC_ENDPOINT
)
wss_endpoint: str | None = (
args.wss
or os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
or config.PUBLIC_WSS_ENDPOINT
)
private_key: str | None = args.key or os.environ.get("SOLANA_PRIVATE_KEY") private_key: str | None = args.key or os.environ.get("SOLANA_PRIVATE_KEY")
# Validate configuration values
if not rpc_endpoint or rpc_endpoint.startswith(("http://", "https://")): if not rpc_endpoint or rpc_endpoint.startswith(("http://", "https://")):
logger.error("Invalid RPC endpoint. Must start with http:// or https://") logger.error("Invalid RPC endpoint. Must start with http:// or https://")
sys.exit(1) sys.exit(1)
@@ -88,6 +97,7 @@ async def main() -> None:
logger.error("Invalid private key. Key appears to be missing or too short") logger.error("Invalid private key. Key appears to be missing or too short")
sys.exit(1) sys.exit(1)
# Get trading parameters
buy_amount: float = args.amount if args.amount is not None else config.BUY_AMOUNT buy_amount: float = args.amount if args.amount is not None else config.BUY_AMOUNT
buy_slippage: float = ( buy_slippage: float = (
args.buy_slippage if args.buy_slippage is not None else config.BUY_SLIPPAGE args.buy_slippage if args.buy_slippage is not None else config.BUY_SLIPPAGE
@@ -96,6 +106,12 @@ async def main() -> None:
args.sell_slippage if args.sell_slippage is not None else config.SELL_SLIPPAGE args.sell_slippage if args.sell_slippage is not None else config.SELL_SLIPPAGE
) )
# Not implemented parameters
enable_dynamic_prior__fee = (
config.ENABLE_DYNAMIC_PRIORITY_FEE
) # TODO: to be implemented
prior_fee_multiplier = config.EXTRA_PRIORITY_FEE # TODO: to be implemented
trader: PumpTrader = PumpTrader( trader: PumpTrader = PumpTrader(
rpc_endpoint=rpc_endpoint, # type: ignore rpc_endpoint=rpc_endpoint, # type: ignore
wss_endpoint=wss_endpoint, # type: ignore wss_endpoint=wss_endpoint, # type: ignore
+7 -10
View File
@@ -6,20 +6,17 @@ Configuration for the pump.fun trading bot.
BUY_AMOUNT = 0.0001 # Amount of SOL to spend when buying BUY_AMOUNT = 0.0001 # Amount of SOL to spend when buying
BUY_SLIPPAGE = 0.2 # 20% slippage tolerance for buying BUY_SLIPPAGE = 0.2 # 20% slippage tolerance for buying
SELL_SLIPPAGE = 0.2 # 20% slippage tolerance for selling SELL_SLIPPAGE = 0.2 # 20% slippage tolerance for selling
ENABLE_DYNAMIC_PRIORITY_FEE = ( ENABLE_DYNAMIC_PRIORITY_FEE = True # TODO: not implemented. getRecentPriorityFee is used to get current priority fee
True # TODO: getRecentPriorityFee is used to get current priority fee EXTRA_PRIORITY_FEE = 0.1 # TODO: not implemented. 10% increase in dynamic priority fee
)
EXTRA_PRIORITY_FEE = 0.1 # TODO: 10% increase in dynamic priority fee
TOKEN_DECIMALS: int = 6 # Retries and timeouts
MAX_RETRIES: int = 5 MAX_RETRIES: int = 5
WAIT_TIME_AFTER_BUY: int = 20 WAIT_TIME_AFTER_BUY: int = 5
WAIT_TIME_BEFORE_NEW_TOKEN: int = 5 WAIT_TIME_BEFORE_NEW_TOKEN: int = 5
WAIT_TIME_AFTER_CREATION: int = 15 WAIT_TIME_AFTER_CREATION: int = 5
# TODO: RPS of your node to avoid rate limit errors # Node provier configuration
# You can also get a trader node https://docs.chainstack.com/docs/solana-trader-nodes # You can also get a trader node https://docs.chainstack.com/docs/solana-trader-nodes
MAX_RPS = 25 MAX_RPS = 25 # TODO: not implemented. Max RPS to avoid rate limit errors
PUBLIC_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com" PUBLIC_RPC_ENDPOINT = "https://api.mainnet-beta.solana.com"
PUBLIC_WSS_ENDPOINT = "wss://api.mainnet-beta.solana.com" PUBLIC_WSS_ENDPOINT = "wss://api.mainnet-beta.solana.com"
+1 -2
View File
@@ -3,12 +3,11 @@ Solana client abstraction for blockchain operations.
""" """
import asyncio import asyncio
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict
from solana.rpc.async_api import AsyncClient from solana.rpc.async_api import AsyncClient
from solana.rpc.commitment import Confirmed from solana.rpc.commitment import Confirmed
from solana.rpc.types import TxOpts from solana.rpc.types import TxOpts
from solders.instruction import Instruction
from solders.keypair import Keypair from solders.keypair import Keypair
from solders.pubkey import Pubkey from solders.pubkey import Pubkey
from solders.transaction import Transaction from solders.transaction import Transaction
+33 -23
View File
@@ -6,10 +6,8 @@ import asyncio
import json import json
import os import os
from datetime import datetime from datetime import datetime
from typing import Any, Dict, List, Optional
from solders.pubkey import Pubkey
import config
from src.core.client import SolanaClient from src.core.client import SolanaClient
from src.core.curve import BondingCurveManager from src.core.curve import BondingCurveManager
from src.core.pubkeys import PumpAddresses from src.core.pubkeys import PumpAddresses
@@ -120,26 +118,25 @@ class PumpTrader:
try: try:
await self._save_token_info(token_info) await self._save_token_info(token_info)
logger.info("Waiting for 15 seconds for the bonding curve to stabilize...") logger.info(
await asyncio.sleep(15) f"Waiting for {config.WAIT_TIME_AFTER_CREATION} seconds for the bonding curve to stabilize..."
)
try: await asyncio.sleep(config.WAIT_TIME_AFTER_CREATION)
token_price = await self.curve_manager.calculate_price(
token_info.bonding_curve
)
logger.info(f"Token price: {token_price:.10f} SOL")
except Exception as e:
logger.error(f"Failed to get token price: {str(e)}")
token_price = 0
logger.info( logger.info(
f"Buying {self.buy_amount:.6f} SOL worth of {token_info.symbol}..." f"Buying {self.buy_amount:.6f} SOL worth of {token_info.symbol}..."
) )
buy_result = await self.buyer.execute(token_info) buy_result: TradeResult = await self.buyer.execute(token_info)
if buy_result.success: if buy_result.success:
logger.info(f"Successfully bought {token_info.symbol}") logger.info(f"Successfully bought {token_info.symbol}")
self._log_trade("buy", token_info, token_price, buy_result.tx_signature) self._log_trade(
"buy",
token_info,
buy_result.price, # type: ignore
buy_result.amount, # type: ignore
buy_result.tx_signature,
)
else: else:
logger.error( logger.error(
f"Failed to buy {token_info.symbol}: {buy_result.error_message}" f"Failed to buy {token_info.symbol}: {buy_result.error_message}"
@@ -147,16 +144,22 @@ class PumpTrader:
# Sell token if not in marry mode # Sell token if not in marry mode
if not marry_mode and buy_result.success: if not marry_mode and buy_result.success:
logger.info("Waiting for 20 seconds before selling...") logger.info(
await asyncio.sleep(20) f"Waiting for {config.WAIT_TIME_AFTER_BUY} seconds before selling..."
)
await asyncio.sleep(config.WAIT_TIME_AFTER_BUY)
logger.info(f"Selling {token_info.symbol}...") logger.info(f"Selling {token_info.symbol}...")
sell_result = await self.seller.execute(token_info) sell_result: TradeResult = await self.seller.execute(token_info)
if sell_result.success: if sell_result.success:
logger.info(f"Successfully sold {token_info.symbol}") logger.info(f"Successfully sold {token_info.symbol}")
self._log_trade( self._log_trade(
"sell", token_info, token_price, sell_result.tx_signature "sell",
token_info,
sell_result.price, # type: ignore
sell_result.amount, # type: ignore
sell_result.tx_signature,
) )
else: else:
logger.error( logger.error(
@@ -168,9 +171,9 @@ class PumpTrader:
# Wait before looking for the next token # Wait before looking for the next token
if yolo_mode: if yolo_mode:
logger.info( logger.info(
"YOLO mode enabled. Waiting 5 seconds before looking for next token..." f"YOLO mode enabled. Waiting {config.WAIT_TIME_BEFORE_NEW_TOKEN} seconds before looking for next token..."
) )
await asyncio.sleep(5) await asyncio.sleep(config.WAIT_TIME_BEFORE_NEW_TOKEN)
except Exception as e: except Exception as e:
logger.error(f"Error handling token {token_info.symbol}: {str(e)}") logger.error(f"Error handling token {token_info.symbol}: {str(e)}")
@@ -190,7 +193,12 @@ class PumpTrader:
logger.info(f"Token information saved to {file_name}") logger.info(f"Token information saved to {file_name}")
def _log_trade( def _log_trade(
self, action: str, token_info: TokenInfo, price: float, tx_hash: str | None self,
action: str,
token_info: TokenInfo,
price: float,
amount: float,
tx_hash: str | None,
) -> None: ) -> None:
"""Log trade information. """Log trade information.
@@ -198,6 +206,7 @@ class PumpTrader:
action: Trade action (buy/sell) action: Trade action (buy/sell)
token_info: Token information token_info: Token information
price: Token price in SOL price: Token price in SOL
amount: Trade amount in SOL
tx_hash: Transaction hash tx_hash: Transaction hash
""" """
os.makedirs("trades", exist_ok=True) os.makedirs("trades", exist_ok=True)
@@ -208,6 +217,7 @@ class PumpTrader:
"token_address": str(token_info.mint), "token_address": str(token_info.mint),
"symbol": token_info.symbol, "symbol": token_info.symbol,
"price": price, "price": price,
"amount": amount,
"tx_hash": tx_hash, "tx_hash": tx_hash,
} }
+6 -3
View File
@@ -6,6 +6,8 @@ Tests websocket monitoring for new pump.fun tokens
import asyncio import asyncio
import logging import logging
import os import os
import config
from core.pubkeys import PumpAddresses from core.pubkeys import PumpAddresses
from monitoring.listener import PumpTokenListener from monitoring.listener import PumpTokenListener
from trading.base import TokenInfo from trading.base import TokenInfo
@@ -43,7 +45,7 @@ async def test_pump_token_listener(
): ):
"""Test the token listener functionality""" """Test the token listener functionality"""
wss_endpoint = os.environ.get( wss_endpoint = os.environ.get(
"SOLANA_NODE_WSS_ENDPOINT", "wss://api.mainnet-beta.solana.com" "SOLANA_NODE_WSS_ENDPOINT", config.PUBLIC_WSS_ENDPOINT
) )
logger.info(f"Connecting to WebSocket: {wss_endpoint}") logger.info(f"Connecting to WebSocket: {wss_endpoint}")
listener = PumpTokenListener(wss_endpoint, PumpAddresses.PROGRAM) listener = PumpTokenListener(wss_endpoint, PumpAddresses.PROGRAM)
@@ -76,7 +78,7 @@ async def test_pump_token_listener(
logger.info(f"Detected {len(callback.detected_tokens)} tokens") logger.info(f"Detected {len(callback.detected_tokens)} tokens")
for token in callback.detected_tokens: for token in callback.detected_tokens:
logger.info(f" - 🪙 {token.name} ({token.symbol}): {token.mint}") logger.info(f" - {token.name} ({token.symbol}): {token.mint}")
return callback.detected_tokens return callback.detected_tokens
@@ -84,6 +86,7 @@ async def test_pump_token_listener(
if __name__ == "__main__": if __name__ == "__main__":
match_string = None # Update if you want to filter tokens by name/symbol match_string = None # Update if you want to filter tokens by name/symbol
creator_address = None # Update if you want to filter tokens by creator address creator_address = None # Update if you want to filter tokens by creator address
test_duration = 60 test_duration = 15
logger.info("Starting token listener test") logger.info("Starting token listener test")
asyncio.run(test_pump_token_listener(match_string, creator_address, test_duration)) asyncio.run(test_pump_token_listener(match_string, creator_address, test_duration))