diff --git a/.env b/.env
index 7e9f218..1f066e6 100644
--- a/.env
+++ b/.env
@@ -27,4 +27,5 @@ OPENAI_API_KEY=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
# aider --model groq/llama3-70b-8192
# List models available from Groq
-# aider --models groq/
\ No newline at end of file
+# aider --models groq/
+SUBSCRIPTION_ID='2217755'
diff --git a/.gitignore b/.gitignore
index 707c6db..1b5f1a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,6 @@ agent-mAId/output.wav
agent-mAId/build/*
agent-mAId/dist/main.exe
agent-mAId/output.wav
-.node-persist/storage/*
\ No newline at end of file
+.node-persist/storage/*
+logs/*
+crypto/sol/.env
diff --git a/crypto/sol/.env b/crypto/sol/.env
index b3f203b..f0b63f2 100644
--- a/crypto/sol/.env
+++ b/crypto/sol/.env
@@ -1,4 +1,7 @@
-SOLANA_NET_URL="wss://api.mainnet-beta.solana.com"
+
+SOLANA_WS_URL="wss://api.mainnet-beta.solana.com"
+SOLANA_WS_URL2="wss://mainnet.rpcpool.com"
+SOLANA_HTTP_URL="https://api.mainnet-beta.solana.com"
DEVELOPER_CHAT_ID="777826553"
# Niki's
# FOLLOWED_WALLET="9U7D916zuQ8qcL9kQZqkcroWhHGho5vD8VNekvztrutN"
diff --git a/crypto/sol/.env.example b/crypto/sol/.env.example
new file mode 100644
index 0000000..e949837
--- /dev/null
+++ b/crypto/sol/.env.example
@@ -0,0 +1,15 @@
+
+SOLANA_WS_URL="wss://api.mainnet-beta.solana.com"
+SOLANA_WS_URL2="wss://mainnet.rpcpool.com"
+SOLANA_HTTP_URL="https://api.mainnet-beta.solana.com"
+DEVELOPER_CHAT_ID="777826553"
+# Niki's
+# FOLLOWED_WALLET="9U7D916zuQ8qcL9kQZqkcroWhHGho5vD8VNekvztrutN"
+# My test Brave sync wallet
+FOLLOWED_WALLET="7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV"
+
+TELEGRAM_BOT_TOKEN="6805059978:AAHNJKuOeazMSJHc3-BXRCsFfEVyFHeFnjw"
+DISPLAY_CURRENCY=USD
+
+YOUR_WALLET="65nzyZXTLC81MthTo52a2gRJjqryTizWVqpK2fDKLye5"
+PK={}
\ No newline at end of file
diff --git a/crypto/sol/app.py b/crypto/sol/app.py
index dd88d3e..cde34d0 100644
--- a/crypto/sol/app.py
+++ b/crypto/sol/app.py
@@ -3,40 +3,108 @@ import websockets
import json
from flask import Flask, render_template, request, jsonify
from solana.rpc.async_api import AsyncClient
-from solana.rpc.commitment import Confirmed
+from solana.transaction import Signature
+from solana.rpc.websocket_api import connect
+from solana.rpc.types import TokenAccountOpts, TxOpts
+from solana.rpc.commitment import Confirmed, Processed
+from solana.transaction import Transaction
+from base64 import b64decode
+import base58
+from solders.rpc.requests import GetTransaction
+from solders.signature import Signature
from solders.pubkey import Pubkey
+from solders.keypair import Keypair
+from solders.transaction import VersionedTransaction
+from solders.transaction import Transaction
+from solders.message import Message
+from solders.instruction import Instruction
+from solders.hash import Hash
+from solders.instruction import CompiledInstruction
+from solders import message
+from jupiter_python_sdk.jupiter import Jupiter, Jupiter_DCA
from dexscreener import DexscreenerClient
from telegram import Bot
from telegram.constants import ParseMode
import datetime
import logging
-from solana.rpc.websocket_api import connect
-from solana.rpc.async_api import AsyncClient
-from solana.rpc.commitment import Confirmed
-from solana.rpc.types import TokenAccountOpts
import base64
import os
-from dotenv import load_dotenv
+from dotenv import load_dotenv,set_key
import aiohttp
from typing import List, Dict
-
-
+import requests
+import threading
+import re
+from typing import List, Dict, Any, Tuple
load_dotenv()
app = Flask(__name__)
-# Use the production Solana RPC endpoint
-solana_client = AsyncClient("https://api.mainnet-beta.solana.com")
-dexscreener_client = DexscreenerClient()
+ENV_FILE = '.env'
+
+async def save_subscription_id(subscription_id):
+ # storing subscription id in .env file disabled
+ #set_key(ENV_FILE, "SUBSCRIPTION_ID", str(subscription_id))
+ logger.info(f"Saved subscription ID: {subscription_id}")
+
+async def load_subscription_id():
+ subscription_id = os.getenv("SUBSCRIPTION_ID")
+ return int(subscription_id) if subscription_id else None
+
+
+
+# Function to find the latest log file
+def get_latest_log_file():
+ log_dir = './logs'
+ try:
+ # 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
+ files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f)) and f.startswith('log_')]
+
+ latest_file = max(files, key=lambda x: os.path.getctime(os.path.join(log_dir, x)))
+ return os.path.join(log_dir, latest_file)
+ except Exception as e:
+ logging.error(f"Error fetching latest log file: {e}")
+ return None
+
+# Flask route to retry processing the last log
+@app.route('/retry-last-log', methods=['GET'])
+def retry_last_log():
+ latest_log_file = get_latest_log_file()
+ if not latest_log_file:
+ return jsonify({"error": "No log files found"}), 404
+
+ try:
+ with open(latest_log_file, 'r') as f:
+ log = json.load(f)
+
+ # await process_log(log)
+ # Run the asynchronous process_log function
+ asyncio.run(process_log(log))
+ return jsonify({"status": "Log dump processed successfully"}), 200
+
+ except Exception as e:
+ logging.error(f"Error processing log dump: {e}")
+ return jsonify({"error": "Failed to process log"}), 500
+
+
+
# Configuration
DEVELOPER_CHAT_ID = os.getenv("DEVELOPER_CHAT_ID")
FOLLOWED_WALLET = os.getenv("FOLLOWED_WALLET")
YOUR_WALLET = os.getenv("YOUR_WALLET")
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
-SOLANA_URL = os.getenv("SOLANA_NET_URL")
+SOLANA_WS_URL = os.getenv("SOLANA_WS_URL")
+SOLANA_HTTP_URL = os.getenv("SOLANA_HTTP_URL")
DISPLAY_CURRENCY = os.getenv('DISPLAY_CURRENCY', 'USD')
+
+# Use the production Solana RPC endpoint
+solana_client = AsyncClient(SOLANA_HTTP_URL)
+dexscreener_client = DexscreenerClient()
+
+
# Initialize Telegram Bot
bot = Bot(token=TELEGRAM_BOT_TOKEN)
@@ -44,46 +112,18 @@ bot = Bot(token=TELEGRAM_BOT_TOKEN)
TOKEN_ADDRESSES = {
"SOL": "So11111111111111111111111111111111111111112",
"USDC": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
- "TARD": "4nfn86ssbv7wiqcsw7bpvn46k24jhe334fudtyxhp1og"
+ "TARD": "4nfn86ssbv7wiqcsw7bpvn46k24jhe334fudtyxhp1og",
}
async def send_telegram_message(message):
try:
await bot.send_message(chat_id=DEVELOPER_CHAT_ID, text=message, parse_mode=ParseMode.HTML)
logging.info(f"Telegram message sent: {message}")
+ # logging.info(f"Telegram message dummy sent: {message}")
except Exception as e:
logging.error(f"Error sending Telegram message: {str(e)}")
-# async def get_token_prices(token_addresses: List[str]) -> Dict[str, float]:
-# url = "https://api.coingecko.com/api/v3/simple/token_price/solana"
-# params = {
-# "contract_addresses": ",".join(token_addresses),
-# "vs_currencies": DISPLAY_CURRENCY.lower()
-# }
-# prices = {}
-
-# async with aiohttp.ClientSession() as session:
-# async with session.get(url, params=params) as response:
-# if response.status == 200:
-# data = await response.json()
-# for address, price_info in data.items():
-# if DISPLAY_CURRENCY.lower() in price_info:
-# prices[address] = price_info[DISPLAY_CURRENCY.lower()]
-# else:
-# logging.error(f"Failed to get token prices. Status: {response.status}")
-
-# # For tokens not found in CoinGecko, try to get price from a DEX or set a default value
-# missing_tokens = set(token_addresses) - set(prices.keys())
-# for token in missing_tokens:
-# # You might want to implement a fallback method here, such as:
-# # prices[token] = await get_price_from_dex(token)
-# # For now, we'll set a default value
-# prices[token] = 0.0
-# logging.warning(f"Price not found for token {token}. Setting to 0.")
-
-# return prices
-
async def get_token_prices(token_addresses: List[str]) -> Dict[str, float]:
coingecko_prices = await get_prices_from_coingecko(token_addresses)
@@ -165,62 +205,70 @@ async def get_sol_price_from_dexscreener() -> float:
prices = await get_prices_from_dexscreener([sol_address])
return prices.get(sol_address, 0.0)
-async def get_sol_price() -> float:
- url = f"https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies={DISPLAY_CURRENCY.lower()}"
- async with aiohttp.ClientSession() as session:
- async with session.get(url) as response:
- if response.status == 200:
- data = await response.json()
- return data['solana'][DISPLAY_CURRENCY.lower()]
- else:
- logging.error(f"Failed to get SOL price. Status: {response.status}")
- return None
-
-async def convert_balances_to_currency(balances, token_prices, sol_price):
- converted_balances = {}
- for token, amount in balances.items():
- if token == 'SOL':
- converted_balances[token] = amount * sol_price
- elif token in token_prices:
- converted_balances[token] = amount * token_prices[token]
- else:
- converted_balances[token] = None # Price not available
- logging.warning(f"Price not available for token {token}")
- return converted_balances
-
-
-
-async def get_token_balance(wallet_address, token_address):
+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 = 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']
- )
- amount = float(balance['result']['value']['uiAmount'])
- logging.debug(f"Balance for {token_address} in {wallet_address}: {amount}")
- return amount
+ 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 Exception as e:
- logging.error(f"Error getting balance for {token_address} in {wallet_address}: {str(e)}")
+ 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
+
-class SolanaEncoder(json.JSONEncoder):
- def default(self, obj):
- if hasattr(obj, '__dict__'):
- return obj.__dict__
- return str(obj)
+async def get_token_name(mint_address):
+ try:
+ token_info = await solana_client.get_account_info_json_parsed(Pubkey.from_string(mint_address))
+ if token_info.value and 'symbol' in token_info.value:
+ return token_info.value['symbol']
+ except Exception as e:
+ logging.error(f"Error fetching token name for {mint_address}: {str(e)}")
+ return None
async def get_wallet_balances(wallet_address):
balances = {}
- token_addresses = []
logging.info(f"Getting balances for wallet: {wallet_address}")
try:
@@ -239,96 +287,80 @@ async def get_wallet_balances(wallet_address):
info = parsed_data['info']
if isinstance(info, dict) and 'mint' in info and 'tokenAmount' in info:
mint = info['mint']
- amount = float(info['tokenAmount']['uiAmount'])
+ #amount = float(info['tokenAmount']['amount']) / (10 ** info['tokenAmount']['decimals'])
+ amount = float(info['tokenAmount']['amount'])/10**info['tokenAmount']['decimals']
+ decimals = info['tokenAmount']['decimals']
if amount > 0:
- token_addresses.append(mint)
- balances[mint] = amount
- logging.debug(f"Balance for {mint}: {amount}")
+ token_name = await get_token_name(mint) or 'Unknown'
+ balances[mint] = {
+ 'name': token_name,
+ 'address': mint,
+ 'amount': amount,
+ 'decimals': decimals
+ }
+ logging.debug(f"Balance for {token_name} ({mint}): {amount}")
else:
logging.warning(f"Unexpected data format for account: {account}")
sol_balance = await solana_client.get_balance(Pubkey.from_string(wallet_address))
if sol_balance.value is not None:
- balances['SOL'] = sol_balance.value / 1e9
+ 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)}")
- return balances, token_addresses
+ return balances
-async def get_converted_balances(wallet_address):
- balances, token_addresses = await get_wallet_balances(wallet_address)
- token_prices = await get_token_prices(token_addresses)
- sol_price = await get_sol_price()
- converted_balances = await convert_balances_to_currency(balances, token_prices, sol_price)
+async def convert_balances_to_currency(balances , sol_price):
+ converted_balances = {}
+ for address, info in balances.items():
+ converted_balance = info.copy() # Create a copy of the original info
+ if info['name'] == 'SOL':
+ converted_balance['value'] = info['amount'] * sol_price
+ elif address in TOKEN_PRICES:
+ converted_balance['value'] = info['amount'] * TOKEN_PRICES[address]
+ else:
+ converted_balance['value'] = None # Price not available
+ logging.warning(f"Price not available for token {info['name']} ({address})")
+ converted_balances[address] = converted_balance
return converted_balances
-
-
-async def send_initial_wallet_states(followed_wallet, your_wallet):
- followed_balances = await get_converted_balances(followed_wallet)
- your_balances = await get_converted_balances(your_wallet)
-
- message = f"Initial Wallet States (Non-zero balances in {DISPLAY_CURRENCY}):\n\n"
- message += f"Followed Wallet ({followed_wallet}):\n"
- for token, amount in followed_balances.items():
- if amount and amount > 0:
- message += f"{token}: {amount:.2f}\n"
-
- message += f"\nYour Wallet ({your_wallet}):\n"
- for token, amount in your_balances.items():
- if amount and amount > 0:
- message += f"{token}: {amount:.2f}\n"
-
- message += "\nMonitored Tokens:\n"
- # Add monitored tokens logic here if needed
-
- await bot.send_message(chat_id=CHAT_ID, text=message)
-
-
-
-async def get_non_zero_token_balances(wallet_address):
- 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(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
+ global TOKEN_ADDRESSES, FOLLOWED_WALLET_VALUE, YOUR_WALLET_VALUE, TOKEN_PRICES
- followed_wallet_balances, followed_token_addresses = await get_wallet_balances(FOLLOWED_WALLET)
- your_wallet_balances, your_token_addresses = await get_wallet_balances(YOUR_WALLET)
+ followed_wallet_balances = await get_wallet_balances(FOLLOWED_WALLET)
+ your_wallet_balances = await get_wallet_balances(YOUR_WALLET)
- all_token_addresses = list(set(followed_token_addresses + your_token_addresses))
- token_prices = await get_token_prices(all_token_addresses)
+ all_token_addresses = list(set(followed_wallet_balances.keys()) | set(your_wallet_balances.keys()))
+ TOKEN_PRICES = await get_token_prices(all_token_addresses)
sol_price = await get_sol_price()
- followed_converted_balances = await convert_balances_to_currency(followed_wallet_balances, token_prices, sol_price)
- your_converted_balances = await convert_balances_to_currency(your_wallet_balances, token_prices, sol_price)
+ followed_converted_balances = await convert_balances_to_currency(followed_wallet_balances, sol_price)
+ your_converted_balances = await convert_balances_to_currency(your_wallet_balances, sol_price)
- TOKEN_ADDRESSES = {token: amount for token, amount in {**followed_converted_balances, **your_converted_balances}.items() if amount is not None and amount > 0}
- logging.info(f"Monitoring balances for tokens: {TOKEN_ADDRESSES.keys()}")
+ TOKEN_ADDRESSES = {address: info for address, info in {**followed_converted_balances, **your_converted_balances}.items() if info['value'] is not None and info['value'] > 0}
+ logging.info(f"Monitoring balances for tokens: {[info['name'] for info in TOKEN_ADDRESSES.values()]}")
followed_wallet_state = []
FOLLOWED_WALLET_VALUE = 0
- for token, amount in followed_converted_balances.items():
- if amount is not None and amount > 0:
- followed_wallet_state.append(f"{token}: {amount:.2f} {DISPLAY_CURRENCY}")
- FOLLOWED_WALLET_VALUE += amount
+ for address, info in followed_converted_balances.items():
+ if info['value'] is not None and info['value'] > 0:
+ followed_wallet_state.append(f"{info['name']} ({address}): {info['value']:.2f} {DISPLAY_CURRENCY}")
+ FOLLOWED_WALLET_VALUE += info['value']
your_wallet_state = []
YOUR_WALLET_VALUE = 0
- for token, amount in your_converted_balances.items():
- if amount is not None and amount > 0:
- your_wallet_state.append(f"{token}: {amount:.2f} {DISPLAY_CURRENCY}")
- YOUR_WALLET_VALUE += amount
+ for address, info in your_converted_balances.items():
+ if info['value'] is not None and info['value'] > 0:
+ your_wallet_state.append(f"{info['name']} ({address}): {info['value']:.2f} {DISPLAY_CURRENCY}")
+ YOUR_WALLET_VALUE += info['value']
message = (
f"Initial Wallet States (All balances in {DISPLAY_CURRENCY}):\n\n"
@@ -339,126 +371,495 @@ async def list_initial_wallet_states():
f"{chr(10).join(your_wallet_state)}\n"
f"Total Value: {YOUR_WALLET_VALUE:.2f} {DISPLAY_CURRENCY}\n\n"
f"Monitored Tokens:\n"
- f"{', '.join(TOKEN_ADDRESSES.keys())}"
+ f"{', '.join([info['name'] for info in TOKEN_ADDRESSES.values()])}"
)
logging.info(message)
await send_telegram_message(message)
+async def get_swap_transaction_details(tx_signature_str):
+ t = await solana_client.get_transaction(Signature.from_string(tx_signature_str), max_supported_transaction_version=0)
+ try:
+ parsed_result = {
+ "order_id": None,
+ "token_in": None,
+ "token_out": None,
+ "amount_in": 0,
+ "amount_out": 0,
+ "amount_in_USD": 0,
+ "amount_out_USD": 0,
+ "percentage_swapped": 0
+ }
+
+ # Extract log messages for order_id and swap details. we have that in the log hook
+ # log_messages = t.value.meta.log_messages
+ # for log in log_messages:
+ # if "order_id" in log:
+ # parsed_result["order_id"] = log.split(":")[1].strip()
+ # break
+
+ instructions = t.value.transaction.transaction.message.instructions
+ # Parse the swap instruction to extract token addresses, amounts, and types
+ for instruction in instructions:
+ if isinstance(instruction, CompiledInstruction):
+ if instruction.program_id == Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"):
+ parsed_info = instruction.parsed.info
+ mint = parsed_info["mint"]
+ amount = float(parsed_info["tokenAmount"]["amount"]) / (10 ** parsed_info["tokenAmount"]["decimals"])
+
+ # Determine token in and token out based on balances
+ if parsed_result["token_in"] is None and amount > 0:
+ parsed_result["token_in"] = mint
+ parsed_result["amount_in"] = amount
+ elif parsed_result["token_out"] is None:
+ parsed_result["token_out"] = mint
+ parsed_result["amount_out"] = amount
+
+ # Calculate USD values if token is USDC
+ if parsed_result["token_in"] == "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v":
+ parsed_result["amount_in_USD"] = parsed_result["amount_in"]
+ if parsed_result["token_out"] == "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v":
+ parsed_result["amount_out_USD"] = parsed_result["amount_out"]
+
+ # Calculate percentage swapped
+ if parsed_result["amount_in"] > 0 and parsed_result["amount_out"] > 0:
+ parsed_result["percentage_swapped"] = (parsed_result["amount_out"] / parsed_result["amount_in"]) * 100
+
+ return parsed_result
+
+ except Exception as e:
+ logging.error(f"Error fetching transaction details: {e}")
+
+ return None
+
+async def get_transaction_details_with_retry(transaction_id, retry_delay = 11, max_retries = 11):
+ # wait for the transaction to be confirmed
+ # await async_client.wait_for_confirmation(Signature.from_string(transaction_id))
+ # qwery every 5 seconds for the transaction details untill not None or 30 seconds
+ for _ in range(max_retries):
+ try:
+ tx_details = await get_transaction_details_rpc(transaction_id)
+ if tx_details is not None:
+ break
+ except Exception as e:
+ logging.error(f"Error fetching transaction details: {e}")
+ logging.info(f"({_} of {max_retries}) Waiting for transaction details for {transaction_id}")
+ await asyncio.sleep(retry_delay)
+ return tx_details
+
+
+async def get_transaction_details_rpc(tx_signature, readfromDump=False):
+
+ try:
+ if readfromDump and os.path.exists('./logs/transation_details.json'):
+ with open('./logs/transation_details.json', 'r') as f: # trump_swap_tr_details
+ transaction_details = json.load(f)
+ return transaction_details
+ else:
+ transaction_details = await solana_jsonrpc("getTransaction", [tx_signature])
+ with open('./logs/transation_details.json', 'w') as f:
+ json.dump(transaction_details, f, indent=2)
+
+ if transaction_details is None:
+ logging.error(f"Error fetching transaction details for {tx_signature}")
+ return None
+
+ # Initialize default result structure
+ parsed_result = {
+ "order_id": None,
+ "token_in": None,
+ "token_out": None,
+ "amount_in": 0,
+ "amount_out": 0,
+ "amount_in_USD": 0,
+ "amount_out_USD": 0,
+ "percentage_swapped": 0
+ }
+
+ # Extract order_id from logs
+ log_messages = transaction_details.get("meta", {}).get("logMessages", [])
+ for log in log_messages:
+ if "order_id" in log:
+ parsed_result["order_id"] = log.split(":")[2].strip()
+ break
+
+ # Extract token transfers from innerInstructions
+ inner_instructions = transaction_details.get('meta', {}).get('innerInstructions', [])
+ for instruction_set in inner_instructions:
+ for instruction in instruction_set.get('instructions', []):
+ if instruction.get('program') == 'spl-token' and instruction.get('parsed', {}).get('type') == 'transferChecked':
+ info = instruction['parsed']['info']
+ mint = info['mint']
+ amount = float(info['tokenAmount']['amount']) / 10 ** info['tokenAmount']['decimals'] # Adjust for decimals
+
+ # Determine which token is being swapped in and out based on zero balances
+ if parsed_result["token_in"] is None and amount > 0:
+ parsed_result["token_in"] = mint
+ parsed_result["amount_in"] = amount
+
+
+ if parsed_result["token_in"] is None or parsed_result["token_out"] is None:
+ # if we've failed to extract token_in and token_out from the transaction details, try a second method
+ inner_instructions = transaction_details.get('meta', {}).get('innerInstructions', [])
+ transfers = []
+
+ for instruction_set in inner_instructions:
+ for instruction in instruction_set.get('instructions', []):
+ if instruction.get('program') == 'spl-token' and instruction.get('parsed', {}).get('type') in ['transfer', 'transferChecked']:
+ info = instruction['parsed']['info']
+ amount = float(info['amount']) if 'amount' in info else float(info['tokenAmount']['amount'])
+ decimals = info['tokenAmount']['decimals'] if 'tokenAmount' in info else 0
+ adjusted_amount = amount / (10 ** decimals)
+ # adjusted_amount = float(info["amount"]) / (10 ** (info["tokenAmount"]["decimals"] if 'tokenAmount' in info else 0))
+ transfers.append({
+ 'mint': info.get('mint'),
+ 'amount': adjusted_amount,
+ 'source': info['source'],
+ 'destination': info['destination']
+ })
+
+ # Identify token_in and token_out
+ if len(transfers) >= 2:
+ parsed_result["token_in"] = transfers[0]['mint']
+ parsed_result["amount_in"] = transfers[0]['amount']
+ parsed_result["token_out"] = transfers[-1]['mint']
+ parsed_result["amount_out"] = transfers[-1]['amount']
+
+ # If mint is not provided, query the Solana network for the account data
+ if parsed_result["token_in"] is None or parsed_result["token_out"] is None:
+ #for transfer in transfers:
+ # do only first and last transfer
+ for transfer in [transfers[0], transfers[-1]]:
+ if transfer['mint'] is None:
+ # Query the Solana network for the account data
+ account_data_result = await solana_jsonrpc("getAccountInfo", [transfer['source']])
+
+ if 'value' in account_data_result and 'data' in account_data_result['value']:
+ account_data_value = account_data_result['value']
+ account_data_data = account_data_value['data']
+ if 'parsed' in account_data_data and 'info' in account_data_data['parsed']:
+ account_data_info = account_data_data['parsed']['info']
+ if 'mint' in account_data_info:
+ transfer['mint'] = account_data_info['mint']
+ if parsed_result["token_in"] is None:
+ parsed_result["token_in"] = transfer['mint']
+ parsed_result["amount_in"] = transfer['amount']/10**6
+ elif parsed_result["token_out"] is None:
+ parsed_result["token_out"] = transfer['mint']
+ parsed_result["amount_out"] = transfer['amount']/10**6
+
+ pre_balalnces = transaction_details.get('meta', {}).get('preTokenBalances', [])
+ for balance in pre_balalnces:
+ if balance['mint'] == parsed_result["token_in"] and balance['owner'] == FOLLOWED_WALLET:
+ parsed_result["before_source_balance"] = float(balance['uiTokenAmount']['amount']) / 10 ** balance['uiTokenAmount']['decimals']
+ break
+
+
+ # Calculate percentage swapped
+ try:
+ if parsed_result["amount_in"] > 0 and 'before_source_balance' in parsed_result and parsed_result["before_source_balance"] > 0:
+ parsed_result["percentage_swapped"] = (parsed_result["amount_in"] / parsed_result["before_source_balance"]) * 100
+ except Exception as e:
+ logging.error(f"Error calculating percentage swapped: {e}")
+
+ return parsed_result
+
+ except requests.exceptions.RequestException as e:
+ print("Error fetching transaction details:", e)
+
+
+async def solana_jsonrpc(method, params = None, jsonParsed = True):
+ # target json example:
+ # data = {
+ # "jsonrpc": "2.0",
+ # "id": 1,
+ # "method": "getTransaction",
+ # "params": [
+ # tx_signature,
+ # {
+ # "encoding": "jsonParsed",
+ # "maxSupportedTransactionVersion": 0
+ # }
+ # ]
+ # }
+
+ data = {
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": method,
+ "params": params or []
+ }
+ data["params"].append({"maxSupportedTransactionVersion": 0})
+ if jsonParsed:
+ data["params"][1]["encoding"] = "jsonParsed"
+
+
+ try:
+ # url = 'https://solana.drpc.org'
+ response = requests.post(SOLANA_HTTP_URL, headers={"Content-Type": "application/json"}, data=json.dumps(data))
+ response.raise_for_status() # Raises an error for bad responses
+ result = response.json()
+ if not 'result' in result or 'error' in result:
+ print("Error fetching data from Solana RPC:", result)
+ return None
+ return result['result']
+ except Exception as e:
+ logging.error(f"Error fetching data from Solana RPC: {e}")
+ return None
+
+
+async def save_log(log):
+ try:
+ os.makedirs('./logs', exist_ok=True)
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")
+ filename = f"./logs/log_{timestamp}.json"
+
+ with open(filename, 'w') as f:
+ json.dump(log, f, indent=2)
+ except Exception as e:
+ logging.error(f"Error saving RPC log: {e}")
+
+
+
+async def process_log(log_result):
+ if log_result['value']['err']:
+ return
+
+ logs = log_result['value']['logs']
+ try:
+ # Detect swap operations in logs
+ swap_operations = ['Program log: Instruction: Swap', 'Program log: Instruction: Swap2', 'Program log: Instruction: SwapExactAmountIn']
+
+ if any(op in logs for op in swap_operations):
+ # Save the log to a file
+ await save_log(log_result)
+ tx_signature_str = log_result['value']['signature']
+
+ before_source_balance = 0
+ source_token_change = 0
+
+ tr_details = {
+ "order_id": None,
+ "token_in": None,
+ "token_out": None,
+ "amount_in": 0,
+ "amount_out": 0,
+ "amount_in_USD": 0,
+ "amount_out_USD": 0,
+ "percentage_swapped": 0
+ }
+ i = 0
+ while i < len(logs):
+ log_entry = logs[i]
+
+ # Check if we found the 'order_id'
+ if tr_details["order_id"] is None and "order_id" in log_entry:
+ # Extract the order_id
+ tr_details["order_id"] = log_entry.split(":")[-1].strip()
+ tr_details["token_in"] = logs[i + 1].split(":")[-1].strip()
+ tr_details["token_out"] = logs[i + 2].split(":")[-1].strip()
+
+ # Look for the token change amounts after tokens have been found
+ if "source_token_change" in log_entry:
+ parts = log_entry.split(", ")
+ for part in parts:
+ if "source_token_change" in part:
+ tr_details["amount_in"] = float(part.split(":")[-1].strip()) / 10 ** 6 # Assuming 6 decimals
+ elif "destination_token_change" in part:
+ tr_details["amount_out"] = float(part.split(":")[-1].strip()) / 10 ** 6 # Assuming 6 decimals
+
+ i += 1
+
+ # calculatte percentage swapped by digging before_source_balance, source_token_change and after_source_balance
+
+ # "Program log: before_source_balance: 19471871, before_destination_balance: 0, amount_in: 19471871, expect_amount_out: 770877527, min_return: 763168752",
+ # "Program log: after_source_balance: 0, after_destination_balance: 770570049",
+ # "Program log: source_token_change: 19471871, destination_token_change: 770570049",
+ if "before_source_balance" in log_entry:
+ parts = log_entry.split(", ")
+ for part in parts:
+ if "before_source_balance" in part:
+ before_source_balance = float(part.split(":")[-1].strip()) / 10 ** 6
+ if "source_token_change" in log_entry:
+ parts = log_entry.split(", ")
+ for part in parts:
+ if "source_token_change" in part:
+ source_token_change = float(part.split(":")[-1].strip()) / 10 ** 6
+
+
+ # GET DETAILS FROM TRANSACTION IF NOT FOUND IN LOGS
+ if tr_details["token_in"] is None or tr_details["token_out"] is None or tr_details["amount_in"] == 0 or tr_details["amount_out"] == 0:
+ logging.warning("Incomplete swap details found in logs. Getting details from transaction")
+ tr_details = await get_transaction_details_info(tx_signature_str, logs)
+ # onlt needed if no details got
+ if before_source_balance > 0 and source_token_change > 0:
+ tr_details["percentage_swapped"] = (source_token_change / before_source_balance) * 100
+ #dirty fix for percentage > 100 (decimals 9 but expecting 6)
+ if tr_details["percentage_swapped"] > 100:
+ tr_details["percentage_swapped"] = tr_details["percentage_swapped"] / 1000
+
+
+ message_text = (
+ f"Swap detected:\n"
+ f"Token In: {tr_details['token_in']}\n"
+ f"Token Out: {tr_details['token_out']}\n"
+ f"Amount In USD: {tr_details['amount_in_USD']}\n"
+ f"Percentage Swapped: {tr_details['percentage_swapped']:.2f}%"
+ )
+
+ await send_telegram_message(message_text)
+ await follow_move(tr_details)
+
+ except Exception as e:
+ logging.error(f"Error processing log: {e}")
+
+
+
+ # "Program log: Instruction: Swap2",
+ # "Program log: order_id: 13985890735038016",
+ # "Program log: AbrMJWfDVRZ2EWCQ1xSCpoVeVgZNpq1U2AoYG98oRXfn", source
+ # "Program log: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", target
+ # "Program log: before_source_balance: 58730110139, before_destination_balance: 202377778, amount_in: 58730110139, expect_amount_out: 270109505, min_return: 267408410",
+ # "Program log: after_source_balance: 0, after_destination_balance: 472509072",
+ # "Program log: source_token_change: 58730110139, destination_token_change: 270131294",
+
+async def get_transaction_details_info(tx_signature_str: str, logs: List[str]) -> Dict[str, Any]:
+
+ try:
+ tr_info = await get_swap_transaction_details(tx_signature_str)
+ except Exception as e:
+ logging.error(f"Error fetching swap transaction details: {e}")
+
+ tr_info = await get_transaction_details_with_retry(tx_signature_str)
+
+ # Fetch token prices
+ token_prices = await get_token_prices([tr_info['token_in'], tr_info['token_out']])
+
+ # Calculate USD values
+ tr_info['amount_in_usd'] = tr_info['amount_in'] * token_prices.get(tr_info['token_in'], 0)
+ tr_info['amount_out_usd'] = tr_info['amount_out'] * token_prices.get(tr_info['token_out'], 0)
+
+ # Calculate the percentage of the source balance that was swapped; ToDo: fix decimals for percentage
+ tr_info['percentage_swapped'] = (tr_info['amount_in'] / tr_info['before_source_balance']) * 100 if tr_info['before_source_balance'] > 0 else 50
+ return tr_info
+
+def _get_pre_balance(transaction_details: Dict[str, Any], token: str) -> float:
+ pre_balances = transaction_details.get('meta', {}).get('preTokenBalances', [])
+ for balance in pre_balances:
+ if balance['mint'] == token:
+ return float(balance['uiTokenAmount']['amount'])
+ return 0.0
+
async def follow_move(move):
- followed_balances = await get_wallet_balances(FOLLOWED_WALLET)
your_balances = await get_wallet_balances(YOUR_WALLET)
-
- if move['token'] not in followed_balances or move['token'] not in your_balances:
- logging.error(f"Invalid token: {move['token']}")
+ your_balance_info = next((balance for balance in your_balances.values() if balance['address'] == move['token_in']), None)
+
+ if not your_balance_info:
+ msg = f"Move Failed:\nNo balance found for token {move['token_in']}"
+ logging.warning(msg)
+ await send_telegram_message(msg)
return
- followed_balance = followed_balances[move['token']]
- your_balance = your_balances[move['token']]
+ your_balance = your_balance_info['amount']
+ token_name = your_balance_info['name']
- proportion = your_balance / followed_balance if followed_balance > 0 else 0
- amount_to_swap = move['amount'] * proportion
+ # move["percentage_swapped"] = (move["amount_out"] / move["amount_in"]) * 100
+ # Calculate the amount to swap based on the same percentage as the followed move
+ amount_to_swap = your_balance * (move['percentage_swapped'] / 100)
+
+ # # always get 99% of the amount to swap
+ # amount_to_swap = amount_to_swap * 0.99
if your_balance >= amount_to_swap:
- # Implement actual swap logic here
- pair = dexscreener_client.get_token_pair("solana", move['token'])
- price = float(pair['priceUsd'])
- received_amount = amount_to_swap * price
+ try:
+ private_key = Keypair.from_bytes(base58.b58decode(os.getenv("PK")))
+ async_client = AsyncClient(SOLANA_WS_URL)
+ jupiter = Jupiter(async_client, private_key)
+
+ # Convert to lamports
+ # if decimals is 6, then amount = amount * 1e6; if 9, then amount = amount * 1e9
+ amount = int(amount_to_swap * 10**your_balance_info['decimals'])
+ transaction_data = await jupiter.swap(
+ input_mint=move['token_in'],
+ output_mint=move['token_out'],
+ amount=amount,
+ slippage_bps=100, # Increased to 1%
+ )
+ raw_transaction = VersionedTransaction.from_bytes(base64.b64decode(transaction_data))
+ signature = private_key.sign_message(message.to_bytes_versioned(raw_transaction.message))
+ signed_txn = VersionedTransaction.populate(raw_transaction.message, [signature])
+ opts = TxOpts(skip_preflight=False, preflight_commitment=Processed)
+ # send the transaction
+ result = await async_client.send_raw_transaction(txn=bytes(signed_txn), opts=opts)
- message = (
- f"Move Followed:\n"
- f"Swapped {amount_to_swap:.6f} {move['token']} "
- f"for {received_amount:.6f} {move['to_token']}"
- )
- logging.info(message)
- await send_telegram_message(message)
+ transaction_id = json.loads(result.to_json())['result']
+ print(f"Follow Transaction Sent: https://solscan.io/tx/{transaction_id}")
+ notification = (
+ f"Move Initiated:\n (decimals: {your_balance_info['decimals']})\n"
+ f"Swapping {move['percentage_swapped']:.2f}% ({amount_to_swap}) {token_name} ({move['token_in']}) "
+ f"for {move['token_out']}"
+ f"\n\nTransaction: {transaction_id}"
+ )
+ logging.info(notification)
+ await send_telegram_message(notification)
+
+ tx_details = await get_transaction_details_with_retry(transaction_id)
+
+ if tx_details is None:
+ logging.info(f"Failed to get transaction details for {transaction_id}")
+ notification = (
+ f"Move Followed:\n"
+ f"Swapped {amount_to_swap:.6f} {token_name} ({move['token_in']}) "
+ f"(same {move['percentage_swapped']:.2f}% as followed wallet)\n"
+ f"\n\nTransaction: {transaction_id}"
+ )
+
+ else:
+ output_token_info = your_balances.get(move['token_out'], {'name': 'Unknown'})
+ output_token_name = output_token_info['name']
+
+ notification = (
+ f"Move Followed:\n"
+ f"Swapped {amount_to_swap:.6f} {token_name} ({move['token_in']}) "
+ f"(same {move['percentage_swapped']:.2f}% as followed wallet)\n"
+ f"for {tx_details['amount_out']:.6f} {output_token_name} ({move['token_out']})"
+ # f"Amount In USD: {tr_details['amount_in_USD']}\n"
+ f"\n\nTransaction: {transaction_id}"
+ )
+ logging.info(notification)
+ await send_telegram_message(notification)
+
+ except Exception as e:
+ error_message = f"Swap Follow Error:\n{str(e)}"
+ logging.error(error_message)
+ # await send_telegram_message(error_message)
else:
- message = (
- f"Move Failed:\n"
- f"Insufficient balance to swap {amount_to_swap:.6f} {move['token']}"
+ msg = (
+ f"Move Not Followed:\n"
+ f"Insufficient balance to swap {amount_to_swap:.6f} {token_name} ({move['token_in']})"
)
- logging.warning(message)
- await send_telegram_message(message)
- followed_balances = await get_wallet_balances(FOLLOWED_WALLET)
- your_balances = await get_wallet_balances(YOUR_WALLET)
-
- if move['token'] not in followed_balances or move['token'] not in your_balances:
- logging.error(f"Invalid token: {move['token']}")
- return
+ logging.warning(msg)
+ await send_telegram_message(msg)
- followed_balance = followed_balances[move['token']]
- your_balance = your_balances[move['token']]
-
- proportion = your_balance / followed_balance if followed_balance > 0 else 0
- amount_to_swap = move['amount'] * proportion
- if your_balance >= amount_to_swap:
- # Implement actual swap logic here
- pair = dexscreener_client.get_token_pair("solana", move['token'])
- price = float(pair['priceUsd'])
- received_amount = amount_to_swap * price
+# Helper functions (implement these according to your needs)
+
- message = (
- f"Move Followed:\n"
- f"Swapped {amount_to_swap:.6f} {move['token']} "
- f"for {received_amount:.6f} {move['to_token']}"
- )
- logging.info(message)
- await send_telegram_message(message)
- else:
- message = (
- f"Move Failed:\n"
- f"Insufficient balance to swap {amount_to_swap:.6f} {move['token']}"
- )
- logging.warning(message)
- await send_telegram_message(message)
async def on_logs(log):
- print(f"Received log: {log}")
- try:
- if 'err' in log and log['err']:
- return
+ logging.debug(f"Received log: {log}")
+ await process_log(log)
- if 'value' in log and 'logs' in log['value']:
- tx = log['value']['signature']
- logs = log['value']['logs']
-
- # Fetch transaction details
- tx_result = await solana_client.get_transaction(tx)
-
- if tx_result and 'result' in tx_result and tx_result['result']:
- transaction = tx_result['result']['transaction']
- message = transaction['message']
-
- for log_entry in logs:
- if 'Program log: Instruction: Swap' in log_entry:
- # Handle swap event
- for instruction in message['instructions']:
- if instruction['programId'] == TOKEN_ADDRESSES['SOL']:
- # This is a token transfer
- from_pubkey = instruction['accounts'][0]
- to_pubkey = instruction['accounts'][1]
- amount = int(instruction['data'], 16) / 1e9 # Convert lamports to SOL
-
- if from_pubkey == FOLLOWED_WALLET:
- move = {
- 'token': 'SOL',
- 'amount': amount,
- 'to_token': 'Unknown' # You might want to determine this based on the receiving address
- }
- await follow_move(move)
-
- # Send a Telegram message about the swap
- message_text = f"Swap detected:\nFrom: {from_pubkey}\nTo: {to_pubkey}\nAmount: {amount} SOL"
- await send_telegram_message(message_text)
- else:
- print(f"Unexpected log format: {log}")
- except:
- print(f"error processing RPC log")
async def subscribe_to_wallet():
- uri = SOLANA_URL
+ SOLANA_ENDPOINTS = [
+ "wss://api.mainnet-beta.solana.com",
+ "wss://solana-api.projectserum.com",
+ "wss://rpc.ankr.com/solana",
+ "wss://mainnet.rpcpool.com",
+ ]
+ uri = SOLANA_WS_URL # wss://api.mainnet-beta.solana.com
reconnect_delay = 5 # Start with a 5-second delay
max_reconnect_delay = 60 # Maximum delay of 60 seconds
@@ -467,6 +868,8 @@ async def subscribe_to_wallet():
async with websockets.connect(uri) as websocket:
logger.info("Connected to Solana websocket")
+ subscription_id = await load_subscription_id()
+
request = {
"jsonrpc": "2.0",
"id": 1,
@@ -488,8 +891,13 @@ async def subscribe_to_wallet():
try:
response = await websocket.recv()
response_data = json.loads(response)
+ logger.debug(f"Received response: {response_data}")
if 'result' in response_data:
- logger.info(f"Subscription successful. Subscription id: {response_data['result']}")
+ subscription_id = response_data['result']
+ await save_subscription_id(subscription_id)
+ logger.info(f"Subscription successful. Subscription id: {subscription_id}")
+ await send_telegram_message("Connected to Solana network. Watching for transactions now.")
+
elif 'params' in response_data:
await on_logs(response_data['params']['result'])
else:
@@ -516,15 +924,31 @@ async def subscribe_to_wallet():
reconnect_delay = min(reconnect_delay * 2, max_reconnect_delay)
-logger = logging.getLogger(__name__)
+logger = logging.getLogger(__name__)
+
+
async def main():
# Initialize logging
logging.basicConfig(level=logging.DEBUG)
- logging.basicConfig(level=logging.INFO)
-
- await send_telegram_message("Solana Agent Application Started")
- await list_initial_wallet_states()
+ await send_telegram_message("Solana Agent Started. Connecting to mainnet...")
+ # await list_initial_wallet_states()
await subscribe_to_wallet()
+def run_flask():
+ # Run Flask app without the reloader, so we can run the async main function
+ app.run(debug=False, port=3001, use_reloader=False)
+
if __name__ == '__main__':
- asyncio.run(main())
\ No newline at end of file
+ # Start Flask in a separate thread
+ flask_thread = threading.Thread(target=run_flask)
+ flask_thread.start()
+
+ # Create an event loop for the async tasks
+ loop = asyncio.get_event_loop()
+ loop.run_until_complete(main())
+ # Start Flask in a separate thread
+ flask_thread = threading.Thread(target=run_flask)
+ flask_thread.start()
+
+ # Run the async main function
+ asyncio.run(main())
diff --git a/crypto/sol/example.rpc.json b/crypto/sol/example.rpc.json
index d0c6adf..b7d6f73 100644
--- a/crypto/sol/example.rpc.json
+++ b/crypto/sol/example.rpc.json
@@ -1,62 +1,136 @@
-{'context': {'slot': 293286129
- }, 'value': {'signature': '2J59rHhGhf8kAvCqyW2bG69KvDxKbh3jKUTPrYvZhgzSk5vAoqTy5NucAW7JC2tK5vTfCLV5UZB6WbwGBbWaBKQ3', 'err': None, 'logs': ['Program ComputeBudget111111111111111111111111111111 invoke [
- 1
- ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [
- 1
- ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
- 1
- ]', 'Program log: Instruction: SharedAccountsRoute', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 2
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 127535 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
- 2
- ]', 'Program log: ray_log: A6XA5awOAAAAAAAAAAAAAAACAAAAAAAAAKXA5awOAAAAXs+S5bOKQADQulmTTwIAAKoshgAAAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 96679 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 89053 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30407 of 113869 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
- 2
- ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 81088 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
- 2
- ]', 'Program log: ray_log: A6oshgAAAAAAAAAAAAAAAAABAAAAAAAAABrmohwAAAAAkAJTsDYEjAC3BYLQ/AIAALJPjoAYAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 54460 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 46743 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30542 of 71786 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
- 2
- ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 38870 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 2
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 34592 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 118828 of 147615 compute units', 'Program return: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 sk+OgBgAAAA=', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success'
- ]
+[
+ {'context': {'slot': 293286129
+ }, 'value': {'signature': '2J59rHhGhf8kAvCqyW2bG69KvDxKbh3jKUTPrYvZhgzSk5vAoqTy5NucAW7JC2tK5vTfCLV5UZB6WbwGBbWaBKQ3', 'err': None, 'logs': ['Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 1
+ ]', 'Program log: Instruction: SharedAccountsRoute', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 127535 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
+ 2
+ ]', 'Program log: ray_log: A6XA5awOAAAAAAAAAAAAAAACAAAAAAAAAKXA5awOAAAAXs+S5bOKQADQulmTTwIAAKoshgAAAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 96679 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 89053 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30407 of 113869 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 81088 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
+ 2
+ ]', 'Program log: ray_log: A6oshgAAAAAAAAAAAAAAAAABAAAAAAAAABrmohwAAAAAkAJTsDYEjAC3BYLQ/AIAALJPjoAYAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 54460 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 46743 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30542 of 71786 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 38870 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 34592 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 118828 of 147615 compute units', 'Program return: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 sk+OgBgAAAA=', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success'
+ ]
+ }
}
-}
error logging: {'context': {'slot': 293286129
- }, 'value': {'signature': '2J59rHhGhf8kAvCqyW2bG69KvDxKbh3jKUTPrYvZhgzSk5vAoqTy5NucAW7JC2tK5vTfCLV5UZB6WbwGBbWaBKQ3', 'err': None, 'logs': ['Program ComputeBudget111111111111111111111111111111 invoke [
- 1
- ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [
- 1
- ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
- 1
- ]', 'Program log: Instruction: SharedAccountsRoute', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 2
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 127535 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
- 2
- ]', 'Program log: ray_log: A6XA5awOAAAAAAAAAAAAAAACAAAAAAAAAKXA5awOAAAAXs+S5bOKQADQulmTTwIAAKoshgAAAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 96679 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 89053 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30407 of 113869 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
- 2
- ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 81088 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
- 2
- ]', 'Program log: ray_log: A6oshgAAAAAAAAAAAAAAAAABAAAAAAAAABrmohwAAAAAkAJTsDYEjAC3BYLQ/AIAALJPjoAYAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 54460 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 3
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 46743 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30542 of 71786 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
- 2
- ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 38870 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
- 2
- ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 34592 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 118828 of 147615 compute units', 'Program return: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 sk+OgBgAAAA=', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success'
- ]
+ }, 'value': {'signature': '2J59rHhGhf8kAvCqyW2bG69KvDxKbh3jKUTPrYvZhgzSk5vAoqTy5NucAW7JC2tK5vTfCLV5UZB6WbwGBbWaBKQ3', 'err': None, 'logs': ['Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 1
+ ]', 'Program log: Instruction: SharedAccountsRoute', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 127535 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
+ 2
+ ]', 'Program log: ray_log: A6XA5awOAAAAAAAAAAAAAAACAAAAAAAAAKXA5awOAAAAXs+S5bOKQADQulmTTwIAAKoshgAAAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 96679 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 89053 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30407 of 113869 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 81088 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
+ 2
+ ]', 'Program log: ray_log: A6oshgAAAAAAAAAAAAAAAAABAAAAAAAAABrmohwAAAAAkAJTsDYEjAC3BYLQ/AIAALJPjoAYAAAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 54460 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 46743 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30542 of 71786 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 38870 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 34592 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 118828 of 147615 compute units', 'Program return: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 sk+OgBgAAAA=', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success'
+ ]
+ }
+ },
+ {'context': {'slot': 293354340
+ }, 'value': {'signature': '3JB8qbmk9Ybb713jpUzHVdYGy3DskfCpeGhoF8PSSdcUCPuqPW9tnuSFSXTHCjZJdLWdL4WxGYLnsaPKAY2NEEJf', 'err': None, 'logs': ['Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [
+ 1
+ ]', 'Program log: CreateIdempotent', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: GetAccountDataSize', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1569 of 283888 compute units', 'Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 11111111111111111111111111111111 invoke [
+ 2
+ ]', 'Program 11111111111111111111111111111111 success', 'Program log: Initialize the associated token account', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: InitializeImmutableOwner', 'Program log: Please upgrade to SPL Token 2022 for immutable owner support', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 277301 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: InitializeAccount3', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4188 of 273419 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 20345 of 289293 compute units', 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 1
+ ]', 'Program log: Instruction: SharedAccountsRoute', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 251725 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c invoke [
+ 2
+ ]', 'Program log: Instruction: Swap', 'Program log: AMM: {
+ "p": 9xERPkyJuPBnffKX2SswG6r25sJMSyD4hTDqgm8d5QoV
+ }', 'Program log: Oracle: {
+ "a": 221333189.0427,
+ "b": 1638750694,
+ "c": 25000000000,
+ "d": 221266809
+ }', 'Program log: Amount: {
+ "in": 100000000,
+ "out": 45171716,
+ "impact": 0.03
+ }', 'Program log: TotalFee: {
+ "fee": 20000,
+ "percent": 0.02
+ }', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 178442 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: MintTo', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4492 of 171397 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 164519 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c consumed 82968 of 239120 compute units', 'Program 2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 153831 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc invoke [
+ 2
+ ]', 'Program log: Instruction: Swap', 'Program log: fee_growth: 9627455162', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 116303 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 108598 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc consumed 45050 of 146166 compute units', 'Program whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 98801 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 invoke [
+ 2
+ ]', 'Program log: ray_log: A9KGPyoAAAAAAAAAAAAAAAABAAAAAAAAACbVb0cAAAAAL7y1hK9GXQBgVYsi7QMAAKRp3ADpAwAA', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 72171 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 64454 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 consumed 30544 of 89499 compute units', 'Program 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 invoke [
+ 2
+ ]', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 471 of 56581 compute units', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 2
+ ]', 'Program log: Instruction: Transfer', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 52303 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 consumed 222659 of 268948 compute units', 'Program return: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 pGncAOkDAAA=', 'Program JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 success'
+ ]
+ }
}
-}
\ No newline at end of file
+]
+
+
+
+
+// new
+DEBUG:websockets.client:< TEXT '{"jsonrpc":"2.0","method":"logsNotification","p...subscription":1135969}}' [5193 bytes]
+Received log: {'context': {'slot': 293522789}, 'value': {'signature': '5YLbNKHr4wRVgYtTHqpWD7HshHWgbxfpXaAU8nKWvTjZvwnNZ5kMqDSuQtzwd6eHZoDKaWkq3FcXbTNe3VhHZT2X', 'err': None, 'logs': ['Program ComputeBudget111111111111111111111111111111 invoke [1]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [1]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program 11111111111111111111111111111111 invoke [1]', 'Program 11111111111111111111111111111111 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [1]', 'Program log: Instruction: InitializeAccount', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3443 of 291550 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 11111111111111111111111111111111 invoke [1]', 'Program 11111111111111111111111111111111 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [1]', 'Program log: Instruction: SyncNative', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3045 of 287957 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke [1]', 'Program log: CreateIdempotent', 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 5838 of 284912 compute units', 'Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success', 'Program 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma invoke [1]', 'Program log: Instruction: Swap2', 'Program log: order_id: 13975709597114048', 'Program log: So11111111111111111111111111111111111111112', 'Program log: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', 'Program log: before_source_balance: 1000000, before_destination_balance: 410923, amount_in: 1000000, expect_amount_out: 136796, min_return: 135429', 'Program log: Dex::MeteoraDlmm amount_in: 1000000, offset: 0', 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [2]', 'Program log: Instruction: Swap', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', 'Program log: Instruction: TransferChecked', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6238 of 205783 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', 'Program log: Instruction: TransferChecked', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6173 of 196112 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo invoke [3]', 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 2136 of 186508 compute units', 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo consumed 58606 of 241445 compute units', 'Program LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo success', 'Program data: QMbN6CYIceINQEIPAAAAAAC5FgAAAAAAAA==', 'Program log: SwapEvent { dex: MeteoraDlmm, amount_in: 1000000, amount_out: 5817 }', 'Program log: Dsk3jzujuXbtA6TBCPwHVdN5LHWmyCqTNWTfbPZWTvDt', 'Program log: GXhNWTQvtXw7hHPrCwiDKex1rRr7g6zDui7hhGTb5XuJ', 'Program log: Dex::RaydiumClmmSwapV2 amount_in: 5817, offset: 18', 'Program CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK invoke [2]', 'Program log: Instruction: SwapV2', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', 'Program log: Instruction: TransferChecked', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6173 of 94632 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]', 'Program log: Instruction: TransferChecked', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6200 of 84589 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program data: QMbN6CYIceLKQf6Jla6jDAa3lvdi80E57zZ2sbaEVINfz/B6mnAddPTnnWLPabh8F9TFvyB2wHgkKjclvP1voW9r2pZM385W5rxgJ6Ti0iTAE+4ET3R0kukR1DtbTAHIU9ZrSlmyVtFIH3U7ixqCaqbGoeydkTdTUUCkOQYTvNcEdWHVAFRzK7kWAAAAAAAAAAAAAAAAAABcFgIAAAAAAAAAAAAAAAAAAQJ4BOyAPFnZBAAAAAAAAABM7IECAAAAAAAAAAAAAAAAWXsAAA==', 'Program CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK consumed 87691 of 159628 compute units', 'Program CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK success', 'Program data: QMbN6CYIceILuRYAAAAAAABcFgIAAAAAAA==', 'Program log: SwapEvent { dex: RaydiumClmmSwapV2, amount_in: 5817, amount_out: 136796 }', 'Program log: GXhNWTQvtXw7hHPrCwiDKex1rRr7g6zDui7hhGTb5XuJ', 'Program log: 5rYBCPjppwZntGzmqMUgC1NVnSc2JdeWXLbZHssE1UyY', 'Program log: after_source_balance: 0, after_destination_balance: 547719', 'Program log: source_token_change: 1000000, destination_token_change: 136796', 'Program 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma consumed 216917 of 279074 compute units', 'Program 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [1]', 'Program log: Instruction: CloseAccount', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2915 of 62157 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success']}}
\ No newline at end of file
diff --git a/crypto/sol/readme.md b/crypto/sol/readme.md
index 6aaad30..d4c989d 100644
--- a/crypto/sol/readme.md
+++ b/crypto/sol/readme.md
@@ -4,6 +4,7 @@ To run this Python Solana agent:
Install the required libraries:
`pip install flask solana dexscreener python-telegram-bot asyncio base58 aiohttp`
+pip install flask dexscreener python-telegram-bot aiohttp requests dotenv websockets solders solana
Replace REPLACE_WITH_WALLET_ADDRESS with the wallet address you want to follow.
Replace REPLACE_WITH_YOUR_WALLET_ADDRESS with your own wallet address.
diff --git a/crypto/sol/transactionExample.json b/crypto/sol/transactionExample.json
new file mode 100644
index 0000000..fbbc586
--- /dev/null
+++ b/crypto/sol/transactionExample.json
@@ -0,0 +1,193 @@
+{
+ 'blockTime': 1728035375,
+'meta': {'computeUnitsConsumed': 128099,
+'err': None, 'fee': 97127, 'innerInstructions': [
+ {'index': 4, 'instructions': [
+ {'accounts': ['7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'A1BBtTYJd4i3xU8D6Tc2FzU6ZN4oXZWXKZnCxwbHXr8x', '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', '8Ggb8th8pZv7eJbRmwkoyrDbSvwLPvMQN7QuHwjm113z', 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'BAxX7eMuSoxF8E4s1Xz5ukcLPHjvfC8Wv9JjSZci7tZ7', 'Gvjgjv63zcQxLbcG2iYF3vcJ2nudRLEffN6hoo8p6Ewy', 'HtsJ5S6K4NM2vXaWZ8k49JAggBgPGrryJ21ezdPBoUC6', 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'So11111111111111111111111111111111111111112', 'DeRo9XMsizey3KWBWS3LHomFC7ZDny1NkFMZUEHgyX8a', 'E6ef1fYRvZ8ejtbdwaK1CDNAgpJxkWZ2pQsL4jaShjNU', '423toqoYT7obTRx8qmwVAeYZfMFRxkwwDzRAwJBd86K3'
+ ], 'data': 'ASCsAbe1UnDmvdhmjnwFdPMzcfkrayiNaFZ61j7FiXYFR5MbydQDnzNL', 'programId': 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK', 'stackHeight': 2
+ },
+ {'parsed': {'info': {'authority': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'destination': 'BAxX7eMuSoxF8E4s1Xz5ukcLPHjvfC8Wv9JjSZci7tZ7', 'mint': 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'source': '8Ggb8th8pZv7eJbRmwkoyrDbSvwLPvMQN7QuHwjm113z', 'tokenAmount': {'amount': '200000000000', 'decimals': 8, 'uiAmount': 2000.0, 'uiAmountString': '2000'
+ }
+ }, 'type': 'transferChecked'
+ }, 'program': 'spl-token', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'stackHeight': 3
+ },
+ {'parsed': {'info': {'authority': '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'destination': 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'mint': 'So11111111111111111111111111111111111111112', 'source': 'Gvjgjv63zcQxLbcG2iYF3vcJ2nudRLEffN6hoo8p6Ewy', 'tokenAmount': {'amount': '32677742', 'decimals': 9, 'uiAmount': 0.032677742, 'uiAmountString': '0.032677742'
+ }
+ }, 'type': 'transferChecked'
+ }, 'program': 'spl-token', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'stackHeight': 3
+ }
+ ]
+ }
+ ], 'logMessages': ['Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program ComputeBudget111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program ComputeBudget111111111111111111111111111111 success', 'Program 11111111111111111111111111111111 invoke [
+ 1
+ ]', 'Program 11111111111111111111111111111111 success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 1
+ ]', 'Program log: Instruction: InitializeAccount', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 3443 of 216550 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma invoke [
+ 1
+ ]', 'Program log: Instruction: Swap2', 'Program log: order_id: 13978787684884160', 'Program log: Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'Program log: So11111111111111111111111111111111111111112', 'Program log: before_source_balance: 4000000000000, before_destination_balance: 0, amount_in: 200000000000, expect_amount_out: 32677742, min_return: 32350965', 'Program log: Dex: :RaydiumClmmSwapV2 amount_in: 200000000000, offset: 0', 'Program CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK invoke [
+ 2
+ ]', 'Program log: Instruction: SwapV2', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: TransferChecked', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6147 of 124210 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 3
+ ]', 'Program log: Instruction: TransferChecked', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6238 of 114194 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success', 'Program data: QMbN6CYIceJeJCSmnTHyq+UhngUSm2ZraA736ls33e54BtTmtKTck18ss0Ijtep7x/QSQpelS9R/BLJJV8nYbkzHEgl6DWzmCqjvYwJou4+wNqo6UT4zu+LS3la0rmchxYO/qAt1QCxsBkiWENlC+V3iQ+9YxPA6ubSXncmJFhG2+Ianct8/LW6f8gEAAAAAAAAAAAAAAAAA0O2QLgAAAAAAAAAAAAAAAKdp93ci1pDdTQAAAAAAAAC1GvfaoAMAAAAAAAAAAAAAQFQBAA==', 'Program CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK consumed 77136 of 178600 compute units', 'Program CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK success', 'Program data: QMbN6CYIceILANDtkC4AAABun/IBAAAAAA==', 'Program log: SwapEvent { dex: RaydiumClmmSwapV2, amount_in: 200000000000, amount_out: 32677742
+ }', 'Program log: 8Ggb8th8pZv7eJbRmwkoyrDbSvwLPvMQN7QuHwjm113z', 'Program log: icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'Program log: after_source_balance: 3800000000000, after_destination_balance: 32677742', 'Program log: source_token_change: 200000000000, destination_token_change: 32677742', 'Program 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma consumed 121291 of 213107 compute units', 'Program 6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma success', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [
+ 1
+ ]', 'Program log: Instruction: CloseAccount', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 2915 of 91816 compute units', 'Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success'
+ ], 'postBalances': [
+ 93712473,
+ 0,
+ 2039280,
+ 72161280,
+ 72161280,
+ 1,
+ 255325042163,
+ 934087680,
+ 1,
+ 1141440,
+ 1705200,
+ 32092560,
+ 13641600,
+ 11637120,
+ 9935565889,
+ 2039280,
+ 1009200,
+ 1141440,
+ 521498880,
+ 617888496398,
+ 1141440
+ ], 'postTokenBalances': [
+ {'accountIndex': 2, 'mint': 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'owner': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'uiTokenAmount': {'amount': '3800000000000', 'decimals': 8, 'uiAmount': 38000.0, 'uiAmountString': '38000'
+ }
+ },
+ {'accountIndex': 14, 'mint': 'So11111111111111111111111111111111111111112', 'owner': '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'uiTokenAmount': {'amount': '9933526609', 'decimals': 9, 'uiAmount': 9.933526609, 'uiAmountString': '9.933526609'
+ }
+ },
+ {'accountIndex': 15, 'mint': 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'owner': '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'uiTokenAmount': {'amount': '2460142552127709', 'decimals': 8, 'uiAmount': 24601425.52127709, 'uiAmountString': '24601425.52127709'
+ }
+ }
+ ], 'preBalances': [
+ 61131858,
+ 0,
+ 2039280,
+ 72161280,
+ 72161280,
+ 1,
+ 255325042163,
+ 934087680,
+ 1,
+ 1141440,
+ 1705200,
+ 32092560,
+ 13641600,
+ 11637120,
+ 9968243631,
+ 2039280,
+ 1009200,
+ 1141440,
+ 521498880,
+ 617888496398,
+ 1141440
+ ], 'preTokenBalances': [
+ {'accountIndex': 2, 'mint': 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'owner': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'uiTokenAmount': {'amount': '4000000000000', 'decimals': 8, 'uiAmount': 40000.0, 'uiAmountString': '40000'
+ }
+ },
+ {'accountIndex': 14, 'mint': 'So11111111111111111111111111111111111111112', 'owner': '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'uiTokenAmount': {'amount': '9966204351', 'decimals': 9, 'uiAmount': 9.966204351, 'uiAmountString': '9.966204351'
+ }
+ },
+ {'accountIndex': 15, 'mint': 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'owner': '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'uiTokenAmount': {'amount': '2459942552127709', 'decimals': 8, 'uiAmount': 24599425.52127709, 'uiAmountString': '24599425.52127709'
+ }
+ }
+ ], 'rewards': [], 'status': {'Ok': None
+ }
+ }, 'slot': 293628136, 'transaction': {'message': {'accountKeys': [
+ {'pubkey': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'signer': True, 'source': 'transaction', 'writable': True
+ },
+ {'pubkey': 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'signer': False, 'source': 'transaction', 'writable': True
+ },
+ {'pubkey': '8Ggb8th8pZv7eJbRmwkoyrDbSvwLPvMQN7QuHwjm113z', 'signer': False, 'source': 'transaction', 'writable': True
+ },
+ {'pubkey': 'DeRo9XMsizey3KWBWS3LHomFC7ZDny1NkFMZUEHgyX8a', 'signer': False, 'source': 'transaction', 'writable': True
+ },
+ {'pubkey': '423toqoYT7obTRx8qmwVAeYZfMFRxkwwDzRAwJBd86K3', 'signer': False, 'source': 'transaction', 'writable': True
+ },
+ {'pubkey': '11111111111111111111111111111111', 'signer': False, 'source': 'transaction', 'writable': False
+ },
+ {'pubkey': 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'signer': False, 'source': 'transaction', 'writable': False
+ },
+ {'pubkey': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'signer': False, 'source': 'transaction', 'writable': False
+ },
+ {'pubkey': 'ComputeBudget111111111111111111111111111111', 'signer': False, 'source': 'transaction', 'writable': False
+ },
+ {'pubkey': '6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma', 'signer': False, 'source': 'transaction', 'writable': False
+ },
+ {'pubkey': 'A1BBtTYJd4i3xU8D6Tc2FzU6ZN4oXZWXKZnCxwbHXr8x', 'signer': False, 'source': 'lookupTable', 'writable': True
+ },
+ {'pubkey': 'HtsJ5S6K4NM2vXaWZ8k49JAggBgPGrryJ21ezdPBoUC6', 'signer': False, 'source': 'lookupTable', 'writable': True
+ },
+ {'pubkey': 'E6ef1fYRvZ8ejtbdwaK1CDNAgpJxkWZ2pQsL4jaShjNU', 'signer': False, 'source': 'lookupTable', 'writable': True
+ },
+ {'pubkey': '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'signer': False, 'source': 'lookupTable', 'writable': True
+ },
+ {'pubkey': 'Gvjgjv63zcQxLbcG2iYF3vcJ2nudRLEffN6hoo8p6Ewy', 'signer': False, 'source': 'lookupTable', 'writable': True
+ },
+ {'pubkey': 'BAxX7eMuSoxF8E4s1Xz5ukcLPHjvfC8Wv9JjSZci7tZ7', 'signer': False, 'source': 'lookupTable', 'writable': True
+ },
+ {'pubkey': 'SysvarRent111111111111111111111111111111111', 'signer': False, 'source': 'lookupTable', 'writable': False
+ },
+ {'pubkey': 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', 'signer': False, 'source': 'lookupTable', 'writable': False
+ },
+ {'pubkey': 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', 'signer': False, 'source': 'lookupTable', 'writable': False
+ },
+ {'pubkey': 'So11111111111111111111111111111111111111112', 'signer': False, 'source': 'lookupTable', 'writable': False
+ },
+ {'pubkey': 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK', 'signer': False, 'source': 'lookupTable', 'writable': False
+ }
+ ], 'addressTableLookups': [
+ {'accountKey': '6ggEfUA8Y2BPkrg6yP2yjjEZRhnF6TyBG8q5tHQvdb2C', 'readonlyIndexes': [
+ 1,
+ 4,
+ 5,
+ 41,
+ 13
+ ], 'writableIndexes': [
+ 27
+ ]
+ },
+ {'accountKey': '9kvMXWLiSBfbGxxrripJP4qZzHatdSbadYCAbwTexN28', 'readonlyIndexes': [], 'writableIndexes': [
+ 17,
+ 18,
+ 12,
+ 13,
+ 15
+ ]
+ }
+ ], 'instructions': [
+ {'accounts': [], 'data': 'JPb7uH', 'programId': 'ComputeBudget111111111111111111111111111111', 'stackHeight': None
+ },
+ {'accounts': [], 'data': '3VbWNdv4R831', 'programId': 'ComputeBudget111111111111111111111111111111', 'stackHeight': None
+ },
+ {'parsed': {'info': {'base': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'lamports': 2039280, 'newAccount': 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'owner': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'seed': '1728035372645', 'source': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'space': 165
+ }, 'type': 'createAccountWithSeed'
+ }, 'program': 'system', 'programId': '11111111111111111111111111111111', 'stackHeight': None
+ },
+ {'parsed': {'info': {'account': 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'mint': 'So11111111111111111111111111111111111111112', 'owner': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'rentSysvar': 'SysvarRent111111111111111111111111111111111'
+ }, 'type': 'initializeAccount'
+ }, 'program': 'spl-token', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'stackHeight': None
+ },
+ {'accounts': ['7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', '8Ggb8th8pZv7eJbRmwkoyrDbSvwLPvMQN7QuHwjm113z', 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'So11111111111111111111111111111111111111112', 'CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK', '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', '8Ggb8th8pZv7eJbRmwkoyrDbSvwLPvMQN7QuHwjm113z', 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'A1BBtTYJd4i3xU8D6Tc2FzU6ZN4oXZWXKZnCxwbHXr8x', '7LVHkVPVosXoWgH1PykWa5PjsfnyBviCdxC8ZUHJDy5U', 'BAxX7eMuSoxF8E4s1Xz5ukcLPHjvfC8Wv9JjSZci7tZ7', 'Gvjgjv63zcQxLbcG2iYF3vcJ2nudRLEffN6hoo8p6Ewy', 'HtsJ5S6K4NM2vXaWZ8k49JAggBgPGrryJ21ezdPBoUC6', 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr', 'Faf89929Ni9fbg4gmVZTca7eW6NFg877Jqn6MizT3Gvw', 'So11111111111111111111111111111111111111112', 'DeRo9XMsizey3KWBWS3LHomFC7ZDny1NkFMZUEHgyX8a', 'E6ef1fYRvZ8ejtbdwaK1CDNAgpJxkWZ2pQsL4jaShjNU', '423toqoYT7obTRx8qmwVAeYZfMFRxkwwDzRAwJBd86K3', '11111111111111111111111111111111'
+ ], 'data': '3sRDYcTeC9Apf4dwtR12F5tp2Pc4P5tDNYNtKqVRGjUmVJ4pEyVYZdwph4vkfkgyChXffRuiYRUXchviqNRXfd5ok6ub9PQK', 'programId': '6m2CDdhRgxpH4WjvdzxAYbGxwdGUz5MziiL5jek2kBma', 'stackHeight': None
+ },
+ {'parsed': {'info': {'account': 'icV5K6iC8J7yyeP9YnJLH2jPRJYT7dBmzm844STxHkP', 'destination': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV', 'owner': '7QXGLRjvyFAmxdRaP9Wk18KwWTMfspF4Na2sr3o3PzxV'
+ }, 'type': 'closeAccount'
+ }, 'program': 'spl-token', 'programId': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'stackHeight': None
+ }
+ ], 'recentBlockhash': 'C2H99uuxKQRWeTngCRZoNHbQ2nDBAA2Uhk2USp7tDX9Z'
+ }, 'signatures': ['3PZLedLDQTb7ddor3XmwbQQycBCgFfMDXHWBRd9rK7gekWTHWetnEGEGpZb6XFep7EbMZFrJweM3q1tkGygZDthB'
+ ]
+ }, 'version': 0
+}
\ No newline at end of file