swap stable again

This commit is contained in:
Dobromir Popov 2024-11-19 14:42:40 +02:00
parent 1b0c72dc08
commit 69241b1498
3 changed files with 82 additions and 40 deletions

View File

@ -24,7 +24,7 @@ TELEGRAM_BOT_TOKEN="6749075936:AAHUHiPTDEIu6JH7S2fQdibwsu6JVG3FNG0"
DISPLAY_CURRENCY=USD
#FOLLOW_AMOUNT=3
# proportional, xx%,
FOLLOW_AMOUNT=5%
FOLLOW_AMOUNT=2%
LIQUIDITY_TOKENS=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v,So11111111111111111111111111111111111111112

View File

@ -14,17 +14,18 @@ from jupiter_python_sdk.jupiter import Jupiter, Jupiter_DCA
from dexscreener import DexscreenerClient
from solana.rpc.types import TokenAccountOpts, TxOpts
from solana.rpc.async_api import AsyncClient
from solana.transaction import Signature
from solana.rpc.websocket_api import connect
from solana.rpc.commitment import Confirmed, Processed
from solana.transaction import Transaction
from solana.rpc.async_api import AsyncClient
from solana.rpc.types import TxOpts
from solana.rpc.commitment import Confirmed, Finalized, Processed
from solana.rpc.core import RPCException
from solana.transaction import Signature, Transaction
from spl.token.client import Token
from base64 import b64decode
import base58
from threading import Thread
from solana.rpc.async_api import AsyncClient
from solana.rpc.types import TxOpts
from solana.rpc.commitment import Confirmed, Finalized, Processed
from solders.rpc.requests import GetTransaction
@ -304,7 +305,9 @@ class SolanaAPI:
finally:
receive_task.cancel()
process_task.cancel()
except asyncio.CancelledError:
logging.info("Websocket connection cancelled, attempting to reconnect...")
await asyncio.sleep(5) # Wait before reconnecting
except Exception as e:
logger.error(f"An unexpected error occurred: {e}")
logger.error("".join(traceback.format_exception(None, e, e.__traceback__)))
@ -361,7 +364,7 @@ class SolanaAPI:
await asyncio.sleep(1)
async def get_token_metadata_symbol(self, mint_address):
if mint_address in DEX.TOKENS_INFO and 'symbol' in DEX.TOKENS_INFO[mint_address]:
if mint_address in DEX.TOKENS_INFO and DEX.TOKENS_INFO[mint_address] is not None:
return DEX.TOKENS_INFO[mint_address].get('symbol')
try:
@ -370,6 +373,8 @@ class SolanaAPI:
account_data_data = account_data_result['value']['data']
if 'parsed' in account_data_data and 'info' in account_data_data['parsed']:
account_data_info = account_data_data['parsed']['info']
if DEX.TOKENS_INFO[mint_address] is None:
DEX.TOKENS_INFO[mint_address] = {}
if 'decimals' in account_data_info:
if mint_address in DEX.TOKENS_INFO:
DEX.TOKENS_INFO[mint_address]['decimals'] = account_data_info['decimals']
@ -780,10 +785,10 @@ class SolanaAPI:
# )
# response_data = response.json()
result = response_data['swapTransaction']
try:
response_data['swapTransaction']
return response_data['swapTransaction']
result = response_data['swapTransaction']
return (response_data['swapTransaction'], response_data['lastValidBlockHeight'])
except:
raise Exception(response_data['error'])
# Return the serialized transaction
@ -793,15 +798,16 @@ class SolanaAPI:
async def follow_move(self,move):
try:
try:
your_balance = 0
your_balances = await DEX.get_wallet_balances(YOUR_WALLET, doGetTokenName=False)
your_balance_info = next((balance for balance in your_balances.values() if balance['address'] == move['token_in']), None)
if your_balance_info is not None:
if your_balance_info is not None and 'amount' in your_balance_info and float(your_balance_info['amount']) > 0:
# Use the balance
print(f"Your balance: {your_balance_info['amount']} {move['symbol_in']}")
# else:
# print(f"No ballance found for {move['symbol_in']}. Skipping move.")
# await telegram_utils.send_telegram_message(f"No ballance found for {move['symbol_in']}. Skipping move.")
# return
else:
print(f"No ballance found for {move['symbol_in']}. Skipping move.")
await telegram_utils.send_telegram_message(f"No ballance found for {move['symbol_in']}. Skipping move.")
return
your_balance = your_balance_info['amount']
@ -812,7 +818,7 @@ class SolanaAPI:
return
except Exception as e:
logging.error(f"Error fetching your balance: {e}")
logging.error(f"Error fetching your balance: {str(e)}", exc_info=True)
if FOLLOW_AMOUNT == 'proportional':
return
@ -898,7 +904,7 @@ class SolanaAPI:
# https://station.jup.ag/api-v6/post-swap
#transaction_data = await jupiter.swap(
transaction_data = await self.swap_on_jupiter(
(transaction_data, block) = await self.swap_on_jupiter(
input_mint=move['token_in'],
output_mint=move['token_out'],
amount=amount_lamports,
@ -933,6 +939,32 @@ class SolanaAPI:
else:
logging.warning(f"Failed to get transaction details for {transaction_id}.\n Probably transaction failed. Retrying again...")
await asyncio.sleep(3)
except RPCException as rpce:
# Convert to string and parse for key information
error_str = str(rpce)
# Get the main error message
if "Error processing Instruction" in error_str:
# Check for common errors
if "insufficient funds" in error_str:
logging.error("Transaction failed: Insufficient funds")
elif "custom program error: 0x28" in error_str:
logging.error("Transaction failed: Custom program error 40 (0x28) - Likely insufficient funds")
# Parse logs if available
try:
logs = rpce.data.result.logs
if logs:
# Get the last error message from logs
error_logs = [log for log in logs if "Error:" in log]
if error_logs:
logging.error(f"Program error: {error_logs[-1]}")
except AttributeError:
pass
# Full debug logging
logging.debug(f"Full RPC error: {error_str}")
except Exception as e:
# decode transacion data (try base58/64)
# decoded_data = base58.b58decode(transaction_data).decode('utf-8')
@ -1070,7 +1102,8 @@ class SolanaDEX:
if 'symbol' not in token_info:
token_info['symbol'] = await SAPI.get_token_metadata_symbol(token)
token_info['price'] = price
token_info['lastUpdated'] = datetime.now().isoformat()
token_info['lastUpdated'] = datetime.now().isoformat()
token_info['address'] = token
return prices
@ -1225,6 +1258,9 @@ class SolanaDEX:
)
if response.value:
if self.TOKENS_INFO is None:
self.TOKENS_INFO = {}
for account in response.value:
try:
parsed_data = account.account.data.parsed
@ -1237,7 +1273,7 @@ class SolanaDEX:
# amount = float(info['tokenAmount']['amount'])
# amount = float(amount / 10**decimals)
token_name = None
if mint in self.TOKENS_INFO:
if mint in self.TOKENS_INFO and isinstance(self.TOKENS_INFO[mint], dict):
token_name = self.TOKENS_INFO[mint].get('symbol')
elif doGetTokenName:
token_name = await SAPI.get_token_metadata_symbol(mint)
@ -1252,27 +1288,31 @@ class SolanaDEX:
self.TOKENS_INFO[mint] = self.TOKENS_INFO[mint].update(balances[mint])
try:
logging.debug(f"Account balance for {token_name or "N/A"} ({mint}): {amount}")
logging.debug(f"Account balance for {token_name or 'N/A'} ({mint}): {amount}")
except Exception as e:
logging.error(f"Error logging account balance: {str(e)}")
logging.error(f"Error logging account balance: {str(e)}", exc_info=True)
else:
logging.warning(f"Unexpected data format for account: {account}")
except Exception as e:
logging.error(f"Error parsing account data: {str(e)}")
logging.error(f"Error parsing account data: {str(e)}", exc_info=True)
self.TOKENS_INFO["lastUpdated"] = datetime.now().isoformat()
# sol_balance = await self.solana_client.get_balance(Pubkey.from_string(wallet_address))
# if sol_balance.value is not None:
# balances['SOL'] = {
# 'name': 'SOL',
# 'address': 'SOL',
# 'amount': sol_balance.value / 1e9
# }
# else:
# logging.warning(f"SOL balance response missing for wallet: {wallet_address}")
sol_balance = await self.solana_client.get_balance(Pubkey.from_string(wallet_address))
if sol_balance.value is not None:
mint = 'So11111111111111111111111111111111111111112'
balances[mint] = {
'name': 'SOL',
'address': mint,
'amount': sol_balance.value / 1e9,
'decimals': 9
}
self.TOKENS_INFO[mint] = {'symbol': token_name}
self.TOKENS_INFO[mint] = self.TOKENS_INFO[mint].update(balances[mint])
else:
logging.warning(f"SOL balance response missing for wallet: {wallet_address}")
except Exception as e:
logging.error(f"Error getting wallet balances: {str(e)} {e.error_msg}")
logging.error(f"Error getting wallet balances: {str(e)}", exc_info=True)
if response and response.value:
logging.info(f"Found {len(response.value)} ({len(balances)} non zero) token accounts for wallet: {wallet_address}")
else:

View File

@ -335,13 +335,15 @@ def init_app(tr_handler=None):
tr["token_out"]
)
# ToDo - optimize
# prices = await SolanaAPI.DEX.get_token_prices(
# [tr["token_in"], tr["token_out"]]
# )
# tr["token_in_price"] = prices.get(tr["token_in"], 0)
# tr["token_out_price"] = prices.get(tr["token_out"], 0)
# tr["value_in_USD"] = prices.get(tr["token_in"], 0) * tr["amount_in"]
# tr["value_out_USD"] = prices.get(tr["token_out"], 0) * tr["amount_out"]
prices = await SolanaAPI.DEX.get_token_prices(
[tr["token_in"], tr["token_out"]]
)
await SolanaAPI.DEX.save_token_info()
tr["token_in_price"] = prices.get(tr["token_in"], 0)
tr["token_out_price"] = prices.get(tr["token_out"], 0)
tr["value_in_USD"] = prices.get(tr["token_in"], 0) * tr["amount_in"]
tr["value_out_USD"] = prices.get(tr["token_out"], 0) * tr["amount_out"]
# notification = f"<b>Got WH notification:</b>: {tr['amount_in']} {tr['symbol_in'] or tr["token_in"]} swapped for {tr['amount_out']} {tr['symbol_out']} ${tr['value_out_USD']}\n"
# logging.info(notification)