tick
This commit is contained in:
parent
b5bc6505a2
commit
019e9f66d4
@ -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
|
||||||
|
|
||||||
@ -580,57 +652,30 @@ 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']
|
|
||||||
|
|
||||||
# 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
|
# 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
|
||||||
@ -639,7 +684,7 @@ async def process_log(log_result):
|
|||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user