From 019e9f66d40a4213492295ee87e74ef241283ede Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Sat, 5 Oct 2024 21:29:45 +0300 Subject: [PATCH] tick --- crypto/sol/app.py | 158 ++++++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 56 deletions(-) diff --git a/crypto/sol/app.py b/crypto/sol/app.py index c8cfb1f..d1e0894 100644 --- a/crypto/sol/app.py +++ b/crypto/sol/app.py @@ -8,6 +8,11 @@ from solana.rpc.websocket_api import connect from solana.rpc.types import TokenAccountOpts, TxOpts from solana.rpc.commitment import Confirmed from solders.pubkey import Pubkey +from solders.keypair import Keypair +from solders.transaction import Transaction +from solders.message import Message +from solders.instruction import Instruction +from solders.hash import Hash from dexscreener import DexscreenerClient from telegram import Bot from telegram.constants import ParseMode @@ -83,7 +88,7 @@ bot = Bot(token=TELEGRAM_BOT_TOKEN) TOKEN_ADDRESSES = { "SOL": "So11111111111111111111111111111111111111112", "USDC": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", - "TARD": "4nfn86ssbv7wiqcsw7bpvn46k24jhe334fudtyxhp1og" + "TARD": "4nfn86ssbv7wiqcsw7bpvn46k24jhe334fudtyxhp1og", } async def send_telegram_message(message): @@ -231,10 +236,20 @@ async def convert_balances_to_currency(balances, token_prices, sol_price): async def get_token_balance(wallet_address, token_address): try: - response = await solana_client.get_token_accounts_by_owner( + response = await solana_client.get_token_accounts_by_owner_json_parsed( Pubkey.from_string(wallet_address), - {"mint": Pubkey.from_string(token_address)} + opts=TokenAccountOpts( + mint=Pubkey.from_string(token_address), + # program_id=Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") + ), + commitment=Confirmed ) + + + # response = await solana_client.get_token_accounts_by_owner( + # Pubkey.from_string(wallet_address), + # {"mint": Pubkey.from_string(token_address)} + # ) if response['result']['value']: balance = await solana_client.get_token_account_balance( response['result']['value'][0]['pubkey'] @@ -250,6 +265,55 @@ async def get_token_balance(wallet_address, token_address): return 0 +async def get_token_balance_rpc(wallet_address, token_address): + url = SOLANA_HTTP_URL + headers = {"Content-Type": "application/json"} + data = { + "jsonrpc": "2.0", + "id": 1, + "method": "getTokenAccountsByOwner", + "params": [ + wallet_address, + { + "mint": token_address + }, + { + "encoding": "jsonParsed" + } + ] + } + try: + response = requests.post(url, headers=headers, data=json.dumps(data)) + response.raise_for_status() # Raises an error for bad responses + accounts = response.json() + + if 'result' in accounts and accounts['result']['value']: + first_account = accounts['result']['value'][0]['pubkey'] + balance_data = { + "jsonrpc": "2.0", + "id": 1, + "method": "getTokenAccountBalance", + "params": [ + first_account + ] + } + balance_response = requests.post(url, headers=headers, data=json.dumps(balance_data)) + balance_response.raise_for_status() + balance = balance_response.json() + + if 'result' in balance and 'value' in balance['result']: + amount = float(balance['result']['value']['uiAmount']) + logging.debug(f"Balance for {token_address} in {wallet_address}: {amount}") + return amount + else: + logging.debug(f"No balance found for {token_address} in {wallet_address}") + return 0 + else: + logging.debug(f"No account found for {token_address} in {wallet_address}") + return 0 + except requests.exceptions.RequestException as e: + logging.error(f"Error getting balance for {token_address} in {wallet_address}: {str(e)} \r\n {e}") + return 0 ENV_FILE = '.env' async def save_subscription_id(subscription_id): @@ -335,16 +399,24 @@ async def send_initial_wallet_states(followed_wallet, your_wallet): async def get_non_zero_token_balances(wallet_address): - non_zero_balances = {} + + followed_wallet_balances, followed_token_addresses = await get_wallet_balances(FOLLOWED_WALLET) + # return non zero balances for followed wallet + non_zero_balances = {token: address for token, address in {**followed_wallet_balances}.items() if address is not None and address > 0} logging.info(f"Getting non-zero balances for wallet: {wallet_address}") - for token, address in TOKEN_ADDRESSES.items(): - balance = await get_token_balance(wallet_address, address) - if balance > 0: - non_zero_balances[token] = address - logging.debug(f"Non-zero balance for {token}: {balance}") return non_zero_balances + # non_zero_balances = {} + # logging.info(f"Getting non-zero balances for wallet: {wallet_address}") + # for token, address in TOKEN_ADDRESSES.items(): + # balance = await get_token_balance_rpc(wallet_address, address) + # if balance > 0: + # non_zero_balances[token] = address + # logging.debug(f"Non-zero balance for {token}: {balance}") + # return non_zero_balances + + async def list_initial_wallet_states(): global TOKEN_ADDRESSES, FOLLOWED_WALLET_VALUE, YOUR_WALLET_VALUE @@ -579,67 +651,40 @@ async def process_log(log_result): for log_entry in logs: if any(op in log_entry for op in swap_operations): - try: - # ++ OLD using solana-py - # # Convert the base58 signature string to bytes - # tx_signature = Signature(b58decode(tx_signature_str)) - # # Fetch transaction details - # tx_result = await solana_client.get_transaction(tx_signature, max_supported_transaction_version=0) - # #tx_result = await get_transaction_details(tx_signature_str) - # if tx_result.value is None: - # logging.error(f"Transaction not found: {tx_signature_str}") - # return - # transaction2 = tx_result.value.transaction - # -- OLD using solana-py - + try: watched_tokens = await get_non_zero_token_balances(FOLLOWED_WALLET) details = parse_swap_logs(logs, watched_tokens) transaction = await get_transaction_details_rpc(tx_signature_str, True) - - # instructions = transaction['transaction']['message']['instructions'] - - # for instruction in instructions: - # from_pubkey, to_pubkey, amount_in, amount_out = extract_swap_details(instruction, logs, watched_tokens) - - # if from_pubkey in watched_tokens.values() or to_pubkey in watched_tokens.values(): - # from_token = determine_token(from_pubkey, watched_tokens) - # to_token = determine_token(to_pubkey, watched_tokens) - - # move = { - # 'token': from_token, - # 'amount': amount_in, - # 'to_token': to_token - # } - # message_text = ( - # f"Swap detected:\n" - # f"From: {from_pubkey} ({from_token})\n" - # f"To: {to_pubkey} ({to_token})\n" - # f"Amount In: {amount_in}\n" - # f"Amount Out: {amount_out}" - # ) - # await send_telegram_message(message_text) - # await follow_move(move) - - tokens = [] - + + tokens = [] # Check inner instructions for transfers and mints for instruction_set in transaction.get('meta', {}).get('innerInstructions', []): for instruction in instruction_set.get('instructions', []): if 'parsed' in instruction and 'info' in instruction['parsed']: info = instruction['parsed']['info'] + amount = None + mint = 'Unknown' + + # Check for amount in transfer and transferChecked instructions if 'amount' in info: amount = info['amount'] - # Assume mint is available for mintTo - mint = info.get('mint', 'Unknown') + elif 'tokenAmount' in info and 'amount' in info['tokenAmount']: + amount = info['tokenAmount']['amount'] + + # Get mint if available + if 'mint' in info: + mint = info['mint'] + + if amount is not None: tokens.append({'amount': amount, 'mint': mint}) # Check post token balances for final token states for balance in transaction.get('postTokenBalances', []): amount = balance['uiTokenAmount']['amount'] mint = balance['mint'] - tokens.append({'amount': amount, 'mint': mint}) + tokens.append({'amount': amount, 'mint': mint}) - # get amount_in, amount_out and token in and token out and USD value + # Get amount_in, amount_out, tokens, and USD value swap_details = { 'amount_in': details['total_amount_in'], 'amount_out': details['total_amount_out'], @@ -649,11 +694,12 @@ async def process_log(log_result): message_text = ( f"Swap detected:\n" f"Amount In: {swap_details['amount_in']}\n" - f"Amount Out: {swap_details['amount_out']}" + f"Amount Out: {swap_details['amount_out']}\n" + f"Tokens: {tokens}" ) await send_telegram_message(message_text) - # await follow_move(move) + await follow_move(swap_details) except Exception as e: logging.error(f"Error fetching transaction details: {e}") @@ -784,7 +830,7 @@ async def main(): # Initialize logging logging.basicConfig(level=logging.DEBUG) await send_telegram_message("Solana Agent Started. Connecting to mainnet...") - # await subscribe_to_wallet() + await subscribe_to_wallet() def run_flask(): # Run Flask app without the reloader, so we can run the async main function