This commit is contained in:
Dobromir Popov 2024-10-05 21:29:45 +03:00
parent b5bc6505a2
commit 019e9f66d4

View File

@ -8,6 +8,11 @@ from solana.rpc.websocket_api import connect
from solana.rpc.types import TokenAccountOpts, TxOpts from solana.rpc.types import TokenAccountOpts, TxOpts
from solana.rpc.commitment import Confirmed from solana.rpc.commitment import Confirmed
from solders.pubkey import Pubkey 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 dexscreener import DexscreenerClient
from telegram import Bot from telegram import Bot
from telegram.constants import ParseMode from telegram.constants import ParseMode
@ -83,7 +88,7 @@ bot = Bot(token=TELEGRAM_BOT_TOKEN)
TOKEN_ADDRESSES = { TOKEN_ADDRESSES = {
"SOL": "So11111111111111111111111111111111111111112", "SOL": "So11111111111111111111111111111111111111112",
"USDC": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "USDC": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"TARD": "4nfn86ssbv7wiqcsw7bpvn46k24jhe334fudtyxhp1og" "TARD": "4nfn86ssbv7wiqcsw7bpvn46k24jhe334fudtyxhp1og",
} }
async def send_telegram_message(message): 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): async def get_token_balance(wallet_address, token_address):
try: 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), 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']: if response['result']['value']:
balance = await solana_client.get_token_account_balance( balance = await solana_client.get_token_account_balance(
response['result']['value'][0]['pubkey'] response['result']['value'][0]['pubkey']
@ -250,6 +265,55 @@ async def get_token_balance(wallet_address, token_address):
return 0 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' ENV_FILE = '.env'
async def save_subscription_id(subscription_id): 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): 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}") 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 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(): async def list_initial_wallet_states():
global TOKEN_ADDRESSES, FOLLOWED_WALLET_VALUE, YOUR_WALLET_VALUE global TOKEN_ADDRESSES, FOLLOWED_WALLET_VALUE, YOUR_WALLET_VALUE
@ -579,67 +651,40 @@ async def process_log(log_result):
for log_entry in logs: for log_entry in logs:
if any(op in log_entry for op in swap_operations): if any(op in log_entry for op in swap_operations):
try: 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
watched_tokens = await get_non_zero_token_balances(FOLLOWED_WALLET) watched_tokens = await get_non_zero_token_balances(FOLLOWED_WALLET)
details = parse_swap_logs(logs, watched_tokens) details = parse_swap_logs(logs, watched_tokens)
transaction = await get_transaction_details_rpc(tx_signature_str, True) transaction = await get_transaction_details_rpc(tx_signature_str, True)
# instructions = transaction['transaction']['message']['instructions'] tokens = []
# 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 = []
# Check inner instructions for transfers and mints # Check inner instructions for transfers and mints
for instruction_set in transaction.get('meta', {}).get('innerInstructions', []): for instruction_set in transaction.get('meta', {}).get('innerInstructions', []):
for instruction in instruction_set.get('instructions', []): for instruction in instruction_set.get('instructions', []):
if 'parsed' in instruction and 'info' in instruction['parsed']: if 'parsed' in instruction and 'info' in instruction['parsed']:
info = instruction['parsed']['info'] info = instruction['parsed']['info']
amount = None
mint = 'Unknown'
# Check for amount in transfer and transferChecked instructions
if 'amount' in info: if 'amount' in info:
amount = info['amount'] amount = info['amount']
# Assume mint is available for mintTo elif 'tokenAmount' in info and 'amount' in info['tokenAmount']:
mint = info.get('mint', 'Unknown') 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}) tokens.append({'amount': amount, 'mint': mint})
# Check post token balances for final token states # Check post token balances for final token states
for balance in transaction.get('postTokenBalances', []): for balance in transaction.get('postTokenBalances', []):
amount = balance['uiTokenAmount']['amount'] amount = balance['uiTokenAmount']['amount']
mint = balance['mint'] 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 = { swap_details = {
'amount_in': details['total_amount_in'], 'amount_in': details['total_amount_in'],
'amount_out': details['total_amount_out'], 'amount_out': details['total_amount_out'],
@ -649,11 +694,12 @@ async def process_log(log_result):
message_text = ( message_text = (
f"Swap detected:\n" f"Swap detected:\n"
f"Amount In: {swap_details['amount_in']}\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 send_telegram_message(message_text)
# await follow_move(move) await follow_move(swap_details)
except Exception as e: except Exception as e:
logging.error(f"Error fetching transaction details: {e}") logging.error(f"Error fetching transaction details: {e}")
@ -784,7 +830,7 @@ async def main():
# Initialize logging # Initialize logging
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG)
await send_telegram_message("Solana Agent Started. Connecting to mainnet...") await send_telegram_message("Solana Agent Started. Connecting to mainnet...")
# await subscribe_to_wallet() await subscribe_to_wallet()
def run_flask(): def run_flask():
# Run Flask app without the reloader, so we can run the async main function # Run Flask app without the reloader, so we can run the async main function