storage commeted

This commit is contained in:
Dobromir Popov
2024-11-18 20:12:58 +02:00
parent fee5b516a1
commit 1b0c72dc08
3 changed files with 419 additions and 313 deletions

View File

@ -48,7 +48,7 @@ import random
import websockets
from typing import Dict, List, Optional
import requests
from datetime import datetime
from datetime import datetime, timedelta
from solana.rpc.types import TokenAccountOpts, TxOpts
from typing import List, Dict, Any, Tuple
import traceback
@ -134,6 +134,9 @@ class SolanaWS:
elif 'error' in response_data:
logger.error(f"Error in WebSocket RPC call: {response_data['error']}")
return None
# if result is integer
elif "id" in response_data and int(response_data['id']) == 1:
return int(response_data['result'])
else:
logger.warning(f"Unexpected response: {response_data}")
return None
@ -789,30 +792,36 @@ class SolanaAPI:
async def follow_move(self,move):
try:
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:
# 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
your_balance = your_balance_info['amount']
try:
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:
# 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
your_balance = your_balance_info['amount']
if not your_balance:
msg = f"<b>Move not followed:</b>\nNo balance found for token {move['symbol_in']}. Cannot follow move."
logging.warning(msg)
await telegram_utils.send_telegram_message(msg)
return
except Exception as e:
logging.error(f"Error fetching your balance: {e}")
if FOLLOW_AMOUNT == 'proportional':
return
token_info = DEX.TOKENS_INFO.get(move['token_in'])
token_name_in = token_info.get('symbol') or await SAPI.get_token_metadata_symbol(move['token_in'])
token_name_out = DEX.TOKENS_INFO[move['token_out']].get('symbol') or await SAPI.get_token_metadata_symbol(move['token_out'])
if not your_balance:
msg = f"<b>Move not followed:</b>\nNo balance found for token {move['symbol_in']}. Cannot follow move."
logging.warning(msg)
await telegram_utils.send_telegram_message(msg)
return
if FOLLOW_AMOUNT == 'percentage':
if FOLLOW_AMOUNT == 'proportional':
# Calculate the amount to swap based on the same percentage as the followed move
if move.get('percentage_swapped') is None:
followed_ballances = await DEX.get_wallet_balances(FOLLOWED_WALLET, doGetTokenName=False)
@ -827,11 +836,20 @@ class SolanaAPI:
amount_to_swap = 100
else:
amount_to_swap = your_balance * (move['percentage_swapped'] / 100)
elif FOLLOW_AMOUNT == 'exact':
amount_to_swap = move['amount_in']
# if contains %, then calculate the amount to swap based on the same percentage as the followed move
elif '%' in FOLLOW_AMOUNT:
try:
percentage = float(FOLLOW_AMOUNT.strip('%'))
amount_to_swap = move['amount_in'] * (percentage / 100)
except ValueError:
msg = f"<b>Move not followed:</b>\nInvalid FOLLOW_AMOUNT '{FOLLOW_AMOUNT}'. Must be 'percentage' or a number."
logging.warning(msg)
await telegram_utils.send_telegram_message(msg)
return
else:
try:
fixed_amount = float(FOLLOW_AMOUNT) # un USD
fixed_amount = float(FOLLOW_AMOUNT) # in USD
fixed_amount_in_token = fixed_amount / move["token_in_price"]
amount_to_swap = min(fixed_amount_in_token, your_balance)
except ValueError:
@ -840,7 +858,7 @@ class SolanaAPI:
await telegram_utils.send_telegram_message(msg)
return
amount_to_swap = min(amount_to_swap, your_balance) # Ensure we're not trying to swap more than we have
# amount_to_swap = min(amount_to_swap, your_balance) # Ensure we're not trying to swap more than we have
decimals = token_info.get('decimals')
# Convert to lamports
@ -848,26 +866,26 @@ class SolanaAPI:
amount_lamports = int(amount_to_swap * 10**decimals)
logging.debug(f"Calculated amount in lamports: {amount_lamports}")
if your_balance < amount_to_swap: # should not happen
msg = (
f"<b>Warning:</b>\n"
f"Insufficient balance: {your_balance:.6f} {token_name_in}. We want to swap {amount_to_swap:.6f}\n({move['symbol_in']}, decimals {token_info.get('decimals')} amount {amount_lamports}).\n This will probably fail. But we will try anyway."
)
logging.warning(msg)
await telegram_utils.send_telegram_message(msg)
# if your_balance < amount_to_swap: # should not happen
# msg = (
# f"<b>Warning:</b>\n"
# f"Insufficient balance: {your_balance:.6f} {token_name_in}. We want to swap {amount_to_swap:.6f}\n({move['symbol_in']}, decimals {token_info.get('decimals')} amount {amount_lamports}).\n This will probably fail. But we will try anyway."
# )
# logging.warning(msg)
# await telegram_utils.send_telegram_message(msg)
try:
try:
notification = (
f"<b>Initiating move:</b>\n"
f"Swapping {amount_to_swap:.2f} {token_name_in} for {token_name_out}"
+ (f" ({move['percentage_swapped']:.2f}%)" if 'percentage_swapped' in move else "")
)
# logging.info(notification)
# error_logger.info(notification)
# await telegram_utils.send_telegram_message(notification)
except Exception as e:
logging.error(f"Error sending notification: {e}")
# try:
# notification = (
# f"<b>Initiating move:</b>\n"
# f"Swapping {amount_to_swap:.2f} {token_name_in} for {token_name_out}"
# + (f" ({move['percentage_swapped']:.2f}%)" if 'percentage_swapped' in move else "")
# )
# # logging.info(notification)
# # error_logger.info(notification)
# # await telegram_utils.send_telegram_message(notification)
# except Exception as e:
# logging.error(f"Error sending notification: {e}")
if self.pk is None:
self.pk = await get_pk()
@ -877,6 +895,7 @@ class SolanaAPI:
async_client = AsyncClient(SOLANA_WS_URL)
jupiter = Jupiter(async_client, private_key)
# https://station.jup.ag/api-v6/post-swap
#transaction_data = await jupiter.swap(
transaction_data = await self.swap_on_jupiter(
@ -889,6 +908,7 @@ class SolanaAPI:
logging.info(f"Initiating move. Transaction data:\n {transaction_data}")
raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data))
# working - no priority fee
signature = private_key.sign_message(message.to_bytes_versioned(raw_transaction.message))
signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature])
@ -896,8 +916,9 @@ class SolanaAPI:
opts = TxOpts(
skip_preflight=False,
preflight_commitment=Processed,
max_retries=5 # Add retries for network issues
)
# send the transaction
result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts)
@ -913,7 +934,10 @@ class SolanaAPI:
logging.warning(f"Failed to get transaction details for {transaction_id}.\n Probably transaction failed. Retrying again...")
await asyncio.sleep(3)
except Exception as e:
decoded_data = ''# base64.b64decode(transaction_data)
# decode transacion data (try base58/64)
# decoded_data = base58.b58decode(transaction_data).decode('utf-8')
# decoded_data = base64.b64decode(transaction_data).decode('utf-8')
decoded_data = None
error_message = f"<b>Move Failed:</b>\n{str(e)}</b>\n{decoded_data}</b>\n{move}"
logging.error(error_message)
# log the errors to /logs/errors.log
@ -1045,7 +1069,8 @@ class SolanaDEX:
token_info = self.TOKENS_INFO.setdefault(token, {})
if 'symbol' not in token_info:
token_info['symbol'] = await SAPI.get_token_metadata_symbol(token)
token_info['price'] = price
token_info['price'] = price
token_info['lastUpdated'] = datetime.now().isoformat()
return prices
@ -1186,6 +1211,10 @@ class SolanaDEX:
asyncio.set_event_loop(loop)
logging.info(f"Getting balances for wallet: {wallet_address}")
response = None
# if ballances got in last 2 minutes, return them
if "lastUpdated" in self.TOKENS_INFO and datetime.fromisoformat(self.TOKENS_INFO["lastUpdated"]) > datetime.now() - timedelta(minutes=2):
logging.info(f"Using cached balances for wallet: {wallet_address}")
return self.TOKENS_INFO
try:
response = await self.solana_client.get_token_accounts_by_owner_json_parsed(
Pubkey.from_string(wallet_address),
@ -1204,46 +1233,46 @@ class SolanaDEX:
if isinstance(info, dict) and 'mint' in info and 'tokenAmount' in info:
mint = info['mint']
decimals = int(info['tokenAmount']['decimals'])
amount = int(info['tokenAmount']['amount'])
amount = int(amount)
if amount > 1:
amount = float(amount / 10**decimals)
if mint in self.TOKENS_INFO:
token_name = self.TOKENS_INFO[mint].get('symbol')
elif doGetTokenName:
token_name = await SAPI.get_token_metadata_symbol(mint) or 'N/A'
self.TOKENS_INFO[mint] = {'symbol': token_name}
await asyncio.sleep(2)
self.TOKENS_INFO[mint]['holdedAmount'] = round(amount, decimals)
self.TOKENS_INFO[mint]['decimals'] = decimals
balances[mint] = {
'name': token_name or 'N/A',
'address': mint,
'amount': amount,
'decimals': decimals
}
try:
logging.debug(f"Account balance for {token_name} ({mint}): {amount}")
except Exception as e:
logging.error(f"Error logging account balance: {str(e)}")
amount = float(info['tokenAmount']['uiAmountString'])
# amount = float(info['tokenAmount']['amount'])
# amount = float(amount / 10**decimals)
token_name = None
if mint in self.TOKENS_INFO:
token_name = self.TOKENS_INFO[mint].get('symbol')
elif doGetTokenName:
token_name = await SAPI.get_token_metadata_symbol(mint)
await asyncio.sleep(2)
balances[mint] = {
'name': token_name or 'N/A',
'address': mint,
'amount': amount,
'decimals': decimals
}
self.TOKENS_INFO[mint] = {'symbol': token_name}
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}")
except Exception as e:
logging.error(f"Error logging account balance: {str(e)}")
else:
logging.warning(f"Unexpected data format for account: {account}")
except Exception as e:
logging.error(f"Error parsing account data: {str(e)}")
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}")
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}")
except Exception as e:
logging.error(f"Error getting wallet balances: {str(e)}")
logging.error(f"Error getting wallet balances: {str(e)} {e.error_msg}")
if response and response.value:
logging.info(f"Found {len(response.value)} ({len(balances)} non zero) token accounts for wallet: {wallet_address}")
else: