This commit is contained in:
Dobromir Popov
2024-10-28 17:15:41 +02:00
parent 885eb523f6
commit 8f6a788717
5 changed files with 145 additions and 143 deletions

1
.gitignore vendored
View File

@ -27,3 +27,4 @@ crypto/sol/logs/error.log
crypto/sol/logs/token_info.json crypto/sol/logs/token_info.json
crypto/sol/logs/transation_details.json crypto/sol/logs/transation_details.json
.env .env
app_data.db

Binary file not shown.

View File

@ -207,161 +207,161 @@ async def process_log(log_result):
async def follow_move_legacy(move): # async def follow_move_legacy(move):
global pk # global pk
if pk is None: # if pk is None:
pk = await get_pk() # pk = await get_pk()
your_balances = await SAPI.dex.get_wallet_balances(YOUR_WALLET, doGetTokenName=False) # your_balances = await SAPI.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) # 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:
# Use the balance # # Use the balance
print(f"Your balance: {your_balance_info['amount']} {move['symbol_in']}") # print(f"Your balance: {your_balance_info['amount']} {move['symbol_in']}")
else: # else:
print(f"No ballance found for {move['symbol_in']}. Skipping move.") # 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.") # await telegram_utils.send_telegram_message(f"No ballance found for {move['symbol_in']}. Skipping move.")
return # return
your_balance = your_balance_info['amount'] # your_balance = your_balance_info['amount']
token_info = SAPI.dex.TOKENS_INFO.get(move['token_in']) # token_info = SAPI.dex.TOKENS_INFO.get(move['token_in'])
token_name_in = token_info.get('symbol') or await SAPI.get_token_metadata(move['token_in']) # token_name_in = token_info.get('symbol') or await SAPI.get_token_metadata(move['token_in'])
token_name_out = SAPI.dex.TOKENS_INFO[move['token_out']].get('symbol') or await SAPI.get_token_metadata_symbol(move['token_out']) # token_name_out = SAPI.dex.TOKENS_INFO[move['token_out']].get('symbol') or await SAPI.get_token_metadata_symbol(move['token_out'])
if not your_balance: # if not your_balance:
msg = f"<b>Move not followed:</b>\nNo balance found for token {move['symbol_in']}. Cannot follow move." # msg = f"<b>Move not followed:</b>\nNo balance found for token {move['symbol_in']}. Cannot follow move."
logging.warning(msg) # logging.warning(msg)
await telegram_utils.send_telegram_message(msg) # await telegram_utils.send_telegram_message(msg)
return # return
if FOLLOW_AMOUNT == 'percentage': # if FOLLOW_AMOUNT == 'percentage':
# Calculate the amount to swap based on the same percentage as the followed move # # Calculate the amount to swap based on the same percentage as the followed move
amount_to_swap = your_balance * (move['percentage_swapped'] / 100) # amount_to_swap = your_balance * (move['percentage_swapped'] / 100)
elif FOLLOW_AMOUNT == 'exact': # elif FOLLOW_AMOUNT == 'exact':
amount_to_swap = move['amount_in'] # amount_to_swap = move['amount_in']
else: # else:
try: # try:
fixed_amount = float(FOLLOW_AMOUNT) # un USD # fixed_amount = float(FOLLOW_AMOUNT) # un USD
fixed_amount_in_token = fixed_amount / move["token_in_price"] # fixed_amount_in_token = fixed_amount / move["token_in_price"]
amount_to_swap = min(fixed_amount_in_token, your_balance) # amount_to_swap = min(fixed_amount_in_token, your_balance)
except ValueError: # except ValueError:
msg = f"<b>Move not followed:</b>\nInvalid FOLLOW_AMOUNT '{FOLLOW_AMOUNT}'. Must be 'percentage' or a number." # msg = f"<b>Move not followed:</b>\nInvalid FOLLOW_AMOUNT '{FOLLOW_AMOUNT}'. Must be 'percentage' or a number."
logging.warning(msg) # logging.warning(msg)
await telegram_utils.send_telegram_message(msg) # await telegram_utils.send_telegram_message(msg)
return # 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') # decimals = token_info.get('decimals')
# Convert to lamports # # Convert to lamports
# if decimals is 6, then amount = amount * 1e6; if 9, then amount = amount * 1e9 # # if decimals is 6, then amount = amount * 1e6; if 9, then amount = amount * 1e9
amount = int(amount_to_swap * 10**decimals) # amount = int(amount_to_swap * 10**decimals)
amount = int(amount) # amount = int(amount)
logging.debug(f"Calculated amount in lamports: {amount}") # logging.debug(f"Calculated amount in lamports: {amount}")
if your_balance < amount_to_swap: # should not happen # if your_balance < amount_to_swap: # should not happen
msg = ( # msg = (
f"<b>Warning:</b>\n" # 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}).\n This will probably fail. But we will try anyway." # 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}).\n This will probably fail. But we will try anyway."
) # )
logging.warning(msg) # logging.warning(msg)
await telegram_utils.send_telegram_message(msg) # await telegram_utils.send_telegram_message(msg)
try: # try:
try: # try:
notification = ( # notification = (
f"<b>Initiating move:</b>\n" # f"<b>Initiating move:</b>\n"
f"Swapping {amount_to_swap:.2f} {token_name_in} for {token_name_out}" # f"Swapping {amount_to_swap:.2f} {token_name_in} for {token_name_out}"
+ (f" ({move['percentage_swapped']:.2f}%)" if 'percentage_swapped' in move else "") # + (f" ({move['percentage_swapped']:.2f}%)" if 'percentage_swapped' in move else "")
) # )
# logging.info(notification) # # logging.info(notification)
# error_logger.info(notification) # # error_logger.info(notification)
await telegram_utils.send_telegram_message(notification) # await telegram_utils.send_telegram_message(notification)
except Exception as e: # except Exception as e:
logging.error(f"Error sending notification: {e}") # logging.error(f"Error sending notification: {e}")
for retry in range(3): # for retry in range(3):
try: # try:
private_key = Keypair.from_bytes(base58.b58decode(pk)) # private_key = Keypair.from_bytes(base58.b58decode(pk))
async_client = AsyncClient(SOLANA_WS_URL) # async_client = AsyncClient(SOLANA_WS_URL)
jupiter = Jupiter(async_client, private_key) # jupiter = Jupiter(async_client, private_key)
transaction_data = await jupiter.swap( # transaction_data = await jupiter.swap(
input_mint=move['token_in'], # input_mint=move['token_in'],
output_mint=move['token_out'], # output_mint=move['token_out'],
amount=amount, # amount=amount,
slippage_bps=300, # Increased to 3% # slippage_bps=300, # Increased to 3%
) # )
logging.info(f"Initiating move. Transaction data:\n {transaction_data}") # logging.info(f"Initiating move. Transaction data:\n {transaction_data}")
error_logger.info(f"Initiating move. Transaction data:\n {transaction_data}") # error_logger.info(f"Initiating move. Transaction data:\n {transaction_data}")
raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data)) # raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data))
message = raw_transaction.message # message = raw_transaction.message
signature = private_key.sign_message(message.to_bytes_versioned()) # signature = private_key.sign_message(message.to_bytes_versioned())
signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature]) # signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature])
opts = TxOpts(skip_preflight=False, preflight_commitment=Processed) # opts = TxOpts(skip_preflight=False, preflight_commitment=Processed)
# send the transaction # # send the transaction
result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts) # result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts)
transaction_id = json.loads(result.to_json())['result'] # transaction_id = json.loads(result.to_json())['result']
print(f"Follow Transaction Sent: https://solscan.io/tx/{transaction_id}") # print(f"Follow Transaction Sent: https://solscan.io/tx/{transaction_id}")
# append to notification # # append to notification
notification += f"\n\n<b>Transaction:</b> <a href='https://solscan.io/tx/{transaction_id}'>{transaction_id}</a>" # notification += f"\n\n<b>Transaction:</b> <a href='https://solscan.io/tx/{transaction_id}'>{transaction_id}</a>"
await telegram_utils.send_telegram_message(f"Follow Transaction Sent: {transaction_id}") # await telegram_utils.send_telegram_message(f"Follow Transaction Sent: {transaction_id}")
tx_details = await SAPI.get_transaction_details_with_retry(transaction_id) # tx_details = await SAPI.get_transaction_details_with_retry(transaction_id)
if tx_details is not None: # if tx_details is not None:
break # break
else: # else:
logging.warning(f"Failed to get transaction details for {transaction_id}. Probably transaction failed. Retrying again...") # logging.warning(f"Failed to get transaction details for {transaction_id}. Probably transaction failed. Retrying again...")
await asyncio.sleep(3) # await asyncio.sleep(3)
except Exception as e: # except Exception as e:
error_message = f"<b>Move Failed:</b>\n{str(e)}</b>\n{transaction_data}</b>\n{move}" # error_message = f"<b>Move Failed:</b>\n{str(e)}</b>\n{transaction_data}</b>\n{move}"
logging.error(error_message) # logging.error(error_message)
# log the errors to /logs/errors.log # # log the errors to /logs/errors.log
error_logger.error(error_message) # error_logger.error(error_message)
error_logger.exception(e) # error_logger.exception(e)
await telegram_utils.send_telegram_message(error_message) # await telegram_utils.send_telegram_message(error_message)
amount = amount * 0.75 # amount = amount * 0.75
await SAPI.dex.get_wallet_balances(YOUR_WALLET, doGetTokenName=False) # await SAPI.dex.get_wallet_balances(YOUR_WALLET, doGetTokenName=False)
try: # try:
if tx_details is None: # if tx_details is None:
logging.info(f"Failed to get transaction details for {transaction_id}") # logging.info(f"Failed to get transaction details for {transaction_id}")
notification = ( # notification = (
f"<b>Move Followed, failed to get transaction details.</b>\n" # f"<b>Move Followed, failed to get transaction details.</b>\n"
f"Swapped {amount_to_swap:.6f} {token_name_in} ({move['token_in']}) " # f"Swapped {amount_to_swap:.6f} {token_name_in} ({move['token_in']}) "
f"(same {move['percentage_swapped']:.2f}% as followed wallet)\n" # f"(same {move['percentage_swapped']:.2f}% as followed wallet)\n"
f"\n\n<b>Transaction:</b> <a href='https://solscan.io/tx/{transaction_id}'>{transaction_id}</a>" # f"\n\n<b>Transaction:</b> <a href='https://solscan.io/tx/{transaction_id}'>{transaction_id}</a>"
# log_successful_swap () # # log_successful_swap ()
) # )
else: # else:
notification = ( # notification = (
f"<b>Move Followed:</b>\n" # f"<b>Move Followed:</b>\n"
f"Swapped {amount_to_swap:.6f} {token_name_in} ({move['symbol_in']}) " # f"Swapped {amount_to_swap:.6f} {token_name_in} ({move['symbol_in']}) "
f"(same {move['percentage_swapped']:.2f}% as followed wallet)\n" # f"(same {move['percentage_swapped']:.2f}% as followed wallet)\n"
f"for {tx_details['amount_out']:.2f} {token_name_out}" # f"for {tx_details['amount_out']:.2f} {token_name_out}"
# f"Amount In USD: {tr_details['amount_in_USD']}\n" # # f"Amount In USD: {tr_details['amount_in_USD']}\n"
f"\n\n<b>Transaction:</b> <a href='https://solscan.io/tx/{transaction_id}'>{transaction_id}</a>" # f"\n\n<b>Transaction:</b> <a href='https://solscan.io/tx/{transaction_id}'>{transaction_id}</a>"
) # )
logging.info(notification) # logging.info(notification)
await telegram_utils.send_telegram_message(notification) # await telegram_utils.send_telegram_message(notification)
except Exception as e: # except Exception as e:
logging.error(f"Error sending notification: {e}") # logging.error(f"Error sending notification: {e}")
except Exception as e: # except Exception as e:
error_message = f"<b>Swap Follow Error:</b>\n{str(e)}" # error_message = f"<b>Swap Follow Error:</b>\n{str(e)}"
logging.error(error_message) # logging.error(error_message)
# log the errors to /logs/errors.log # # log the errors to /logs/errors.log
error_logger.error(error_message) # error_logger.error(error_message)
error_logger.exception(e) \ # error_logger.exception(e) \
# if error_message contains 'Program log: Error: insufficient funds' # # if error_message contains 'Program log: Error: insufficient funds'
if 'insufficient funds' in error_message: # if 'insufficient funds' in error_message:
await telegram_utils.send_telegram_message("Insufficient funds. Cannot follow move. Please check your balance.") # await telegram_utils.send_telegram_message("Insufficient funds. Cannot follow move. Please check your balance.")
else: # else:
await telegram_utils.send_telegram_message(error_message) # await telegram_utils.send_telegram_message(error_message)
# Helper functions # Helper functions
@ -401,7 +401,8 @@ async def process_messages(websocket):
pk = None pk = None
app = init_app(follow_move_legacy) app = init_app()
# app = init_app(follow_move_legacy)
# Convert Flask app to ASGI # Convert Flask app to ASGI
asgi_app = WsgiToAsgi(app) asgi_app = WsgiToAsgi(app)

View File

@ -276,15 +276,15 @@ class SolanaAPI:
if solana_ws.websocket: if solana_ws.websocket:
await solana_ws.close() await solana_ws.close()
await async_safe_call(self.on_bot_message,"Reconnecting...") await async_safe_call(self.on_bot_message,"Reconnecting...")
if self.receive_task and not self.receive_task.cancelled(): if receive_task and not receive_task.cancelled():
receive_task.cancel() receive_task.cancel()
if self.process_task and not self.process_task.cancelled(): if process_task and not process_task.cancelled():
process_task.cancel() process_task.cancel()
except Exception as e: except Exception as e:
logger.error(f"An error occurred while unsubscribing: {e}") logger.error(f"An error occurred while unsubscribing: {e}")
finally: finally:
self.receive_task = None receive_task = None
self.process_task = None process_task = None
await asyncio.sleep(5) await asyncio.sleep(5)

View File

@ -304,7 +304,7 @@ def get_latest_log_file(wh:bool):
# files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f))] # files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f))]
# filter files mask log_20241005_004103_143116.json # filter files mask log_20241005_004103_143116.json
if wh: if wh:
files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f)) and f.startswith('wh-')] files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f)) and f.startswith('wh_')]
else: else:
files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f)) and f.startswith('log_')] files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f)) and f.startswith('log_')]