replay
This commit is contained in:
parent
8c75d1b650
commit
a2b775029a
@ -23,7 +23,7 @@ TELEGRAM_BOT_TOKEN="6749075936:AAHUHiPTDEIu6JH7S2fQdibwsu6JVG3FNG0"
|
|||||||
|
|
||||||
DISPLAY_CURRENCY=USD
|
DISPLAY_CURRENCY=USD
|
||||||
FOLLOW_AMOUNT=2
|
FOLLOW_AMOUNT=2
|
||||||
FOLLOW_AMOUNT=percentage
|
#FOLLOW_AMOUNT=percentage
|
||||||
|
|
||||||
LIQUIDITY_TOKENS=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v,So11111111111111111111111111111111111111112
|
LIQUIDITY_TOKENS=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v,So11111111111111111111111111111111111111112
|
||||||
|
|
||||||
|
@ -2,37 +2,56 @@ import sys
|
|||||||
import os
|
import os
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
import json
|
from typing import NamedTuple
|
||||||
|
|
||||||
|
class Transaction(NamedTuple):
|
||||||
|
wallet: str
|
||||||
|
transaction_type: str
|
||||||
|
symbol_in: str
|
||||||
|
amount_in: float
|
||||||
|
value_in_usd: float
|
||||||
|
symbol_out: str
|
||||||
|
amount_out: float
|
||||||
|
value_out_usd: float
|
||||||
|
tx_signature: str
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import prisma
|
from enum import Enum
|
||||||
|
import json
|
||||||
from prisma import Prisma
|
from prisma import Prisma
|
||||||
|
|
||||||
|
class TransactionStatus(Enum):
|
||||||
|
PENDING = "PENDING"
|
||||||
|
SENT = "SENT"
|
||||||
|
CONFIRMED = "CONFIRMED"
|
||||||
|
|
||||||
# Initialize the Prisma client
|
# Initialize the Prisma client
|
||||||
prisma_client = Prisma()
|
prisma_client = Prisma()
|
||||||
|
|
||||||
async def init_db():
|
async def init_db():
|
||||||
await prisma_client.connect()
|
await prisma_client.connect()
|
||||||
|
|
||||||
async def store_transaction(transaction_data):
|
async def store_transaction(transaction: Transaction):
|
||||||
"""
|
"""
|
||||||
Store a transaction record in the database using a dictionary.
|
Store a transaction record in the database.
|
||||||
"""
|
"""
|
||||||
default_data = {
|
await prisma_client.transaction.create(
|
||||||
'wallet_id': None,
|
data={
|
||||||
|
'wallet_id': transaction.wallet,
|
||||||
'timestamp': datetime.now().isoformat(),
|
'timestamp': datetime.now().isoformat(),
|
||||||
'type': None,
|
'type': transaction.transaction_type,
|
||||||
'sell_currency': None,
|
'sell_currency': transaction.symbol_in,
|
||||||
'sell_amount': 0.0,
|
'sell_amount': transaction.amount_in,
|
||||||
'sell_value': 0.0,
|
'sell_value': transaction.value_in_usd,
|
||||||
'buy_currency': None,
|
'buy_currency': transaction.symbol_out,
|
||||||
'buy_amount': 0.0,
|
'buy_amount': transaction.amount_out,
|
||||||
'buy_value': 0.0,
|
'buy_value': transaction.value_out_usd,
|
||||||
'solana_signature': None,
|
'solana_signature': transaction.tx_signature,
|
||||||
'details': json.dumps({}),
|
'details': json.dumps({}),
|
||||||
'status': prisma_client.transactionStatus.ORIGINAL
|
'status': TransactionStatus.PENDING.value
|
||||||
}
|
}
|
||||||
default_data.update(transaction_data)
|
)
|
||||||
await prisma_client.transaction.create(data=default_data)
|
|
||||||
|
|
||||||
async def update_holdings(wallet_id, currency, amount_change):
|
async def update_holdings(wallet_id, currency, amount_change):
|
||||||
holding = await prisma_client.holding.find_first(
|
holding = await prisma_client.holding.find_first(
|
||||||
|
@ -3,6 +3,7 @@ import sys
|
|||||||
import asyncio
|
import asyncio
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
|
import traceback
|
||||||
from flask import Flask, jsonify, request, render_template, redirect, url_for
|
from flask import Flask, jsonify, request, render_template, redirect, url_for
|
||||||
# from flask_oauthlib.client import OAuth
|
# from flask_oauthlib.client import OAuth
|
||||||
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
|
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
|
||||||
@ -76,15 +77,48 @@ def init_app(tr_handler=None):
|
|||||||
await utils.telegram_utils.send_telegram_message(notification)
|
await utils.telegram_utils.send_telegram_message(notification)
|
||||||
|
|
||||||
# Store the notified transaction in the database
|
# Store the notified transaction in the database
|
||||||
await storage.store_transaction(wallet, "SWAP", tr['symbol_in'] , tr['amount_in'], tr['value_in_USD'], tr['symbol_out'], tr['amount_out'], tr['value_out_USD'], tx_signature)
|
original_transaction = storage.Transaction(
|
||||||
|
wallet=wallet,
|
||||||
|
transaction_type="SWAP",
|
||||||
|
symbol_in=tr['symbol_in'],
|
||||||
|
amount_in=tr['amount_in'],
|
||||||
|
value_in_usd=tr['value_in_USD'],
|
||||||
|
symbol_out=tr['symbol_out'],
|
||||||
|
amount_out=tr['amount_out'],
|
||||||
|
value_out_usd=tr['value_out_USD'],
|
||||||
|
tx_signature=tx_signature
|
||||||
|
)
|
||||||
|
await storage.store_transaction(original_transaction)
|
||||||
# Attempt to execute the copytrade transaction
|
# Attempt to execute the copytrade transaction
|
||||||
try:
|
try:
|
||||||
await SolanaAPI.SAPI.follow_move(tr)
|
await SolanaAPI.SAPI.follow_move(tr)
|
||||||
# Store the successful copytrade transaction
|
# Store the successful copytrade transaction
|
||||||
await storage.store_transaction(wallet, "SWAP", tr['symbol_in'] , tr['amount_in'], tr['value_in_USD'], tr['symbol_out'], tr['amount_out'], tr['value_out_USD'],tx_signature)
|
follow_transaction = storage.Transaction(
|
||||||
|
wallet=wallet,
|
||||||
|
transaction_type="SWAP",
|
||||||
|
symbol_in=tr['symbol_in'],
|
||||||
|
amount_in=tr['amount_in'],
|
||||||
|
value_in_usd=tr['value_in_USD'],
|
||||||
|
symbol_out=tr['symbol_out'],
|
||||||
|
amount_out=tr['amount_out'],
|
||||||
|
value_out_usd=tr['value_out_USD'],
|
||||||
|
tx_signature=tx_signature
|
||||||
|
)
|
||||||
|
await storage.store_transaction(follow_transaction)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Store the failed copytrade transaction
|
# Store the failed copytrade transaction
|
||||||
await storage.store_transaction(wallet, "SWAP_FAIL", tr['symbol_in'] , tr['amount_in'], tr['value_in_USD'], tr['symbol_out'], tr['amount_out'], tr['value_out_USD'],tx_signature)
|
failed_transaction = storage.Transaction(
|
||||||
|
wallet=wallet,
|
||||||
|
transaction_type="SWAP_FAIL",
|
||||||
|
symbol_in=tr['symbol_in'],
|
||||||
|
amount_in=tr['amount_in'],
|
||||||
|
value_in_usd=tr['value_in_USD'],
|
||||||
|
symbol_out=tr['symbol_out'],
|
||||||
|
amount_out=tr['amount_out'],
|
||||||
|
value_out_usd=tr['value_out_USD'],
|
||||||
|
tx_signature=tx_signature
|
||||||
|
)
|
||||||
|
await storage.store_transaction(failed_transaction)
|
||||||
logging.error(f"Copytrade transaction failed: {e}")
|
logging.error(f"Copytrade transaction failed: {e}")
|
||||||
# ToDo - probably optimize
|
# ToDo - probably optimize
|
||||||
await SolanaAPI.SAPI.save_token_info()
|
await SolanaAPI.SAPI.save_token_info()
|
||||||
@ -153,42 +187,64 @@ def init_app(tr_handler=None):
|
|||||||
token_inputs = swap_event.get('tokenInputs', [])
|
token_inputs = swap_event.get('tokenInputs', [])
|
||||||
token_outputs = swap_event.get('tokenOutputs', [])
|
token_outputs = swap_event.get('tokenOutputs', [])
|
||||||
|
|
||||||
if not token_inputs or not token_outputs:
|
|
||||||
logging.warning("Missing token inputs or outputs")
|
|
||||||
return
|
|
||||||
|
|
||||||
usdcMint = LIQUIDITY_TOKENS[0]
|
usdcMint = LIQUIDITY_TOKENS[0]
|
||||||
tr = {}
|
tr = {}
|
||||||
|
wallet = data[0]['feePayer'] # Using feePayer as the wallet address
|
||||||
|
tx_signature = data[0]['signature']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Determine transaction type
|
||||||
|
if token_inputs and token_outputs and LIQUIDITY_TOKENS[0] in [token_inputs[0]["mint"], token_outputs[0]["mint"]]:
|
||||||
|
if token_inputs[0]["mint"] == usdcMint:
|
||||||
|
tr["type"] = "BUY"
|
||||||
|
else:
|
||||||
|
tr["type"] = "SELL"
|
||||||
|
else:
|
||||||
|
tr["type"] = "SWAP"
|
||||||
|
|
||||||
if not token_inputs or len(token_inputs) == 0:
|
if not token_inputs or len(token_inputs) == 0:
|
||||||
logging.info("Assumed USDC as first token. BUY transaction detected")
|
logging.info("Assumed USDC as first token. BUY transaction detected")
|
||||||
tr["token_in"] = usdcMint
|
tr["token_in"] = usdcMint
|
||||||
tr["type"] = "BUY"
|
tr["type"] = "BUY"
|
||||||
tr["amount_in"] = await SolanaAPI.DEX.get_token_prices(
|
prices = await SolanaAPI.DEX.get_token_prices([token_outputs[0]["mint"]])
|
||||||
token_outputs[0]["mint"],
|
tr["amount_in"] = prices[token_outputs[0]["mint"]] * int(token_outputs[0]["rawTokenAmount"]["tokenAmount"]) / 10** int(token_outputs[0]["rawTokenAmount"]["decimals"])
|
||||||
int(token_outputs[0]["rawTokenAmount"]["tokenAmount"])
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
token_in = token_inputs[0]
|
token_in = token_inputs[0]
|
||||||
tr["token_in"] = token_in["mint"]
|
tr["token_in"] = token_in["mint"]
|
||||||
tr["token_in_decimals"] = token_in["rawTokenAmount"]["decimals"]
|
tr["token_in_decimals"] = token_in["rawTokenAmount"]["decimals"]
|
||||||
tr["amount_in"] = float(int(token_in["rawTokenAmount"]["tokenAmount"]) / 10**token_in["rawTokenAmount"]["decimals"])
|
tr["amount_in"] = float(int(token_in["rawTokenAmount"]["tokenAmount"]) / 10**token_in["rawTokenAmount"]["decimals"])
|
||||||
# 'amount_in': float(token_inputs[0]['rawTokenAmount']['tokenAmount']) / 10**token_inputs[0]['rawTokenAmount']['decimals'],
|
|
||||||
|
|
||||||
if not token_outputs or len(token_outputs) == 0:
|
if not token_outputs or len(token_outputs) == 0:
|
||||||
logging.info("Assumed USDC as second token. SELL transaction detected")
|
logging.info("Assumed USDC as second token. SELL transaction detected")
|
||||||
tr["token_out"] = usdcMint
|
tr["token_out"] = usdcMint
|
||||||
tr["type"] = "SELL"
|
tr["type"] = "SELL"
|
||||||
tr["amount_out"] = await SolanaAPI.DEX.get_token_prices(
|
prices = await SolanaAPI.DEX.get_token_prices([token_inputs[0]["mint"]])
|
||||||
token_inputs[0]["mint"],
|
tr["amount_out"] = prices[token_inputs[0]["mint"]] * int(token_inputs[0]["rawTokenAmount"]["tokenAmount"]) / 10** int(token_inputs[0]["rawTokenAmount"]["decimals"])
|
||||||
int(token_inputs[0]["rawTokenAmount"]["tokenAmount"])
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
token_out = token_outputs[0]
|
token_out = token_outputs[0]
|
||||||
tr["token_out"] = token_out["mint"]
|
tr["token_out"] = token_out["mint"]
|
||||||
tr["token_out_decimals"] = token_out["rawTokenAmount"]["decimals"]
|
tr["token_out_decimals"] = token_out["rawTokenAmount"]["decimals"]
|
||||||
tr["amount_out"] = float(int(token_out["rawTokenAmount"]["tokenAmount"]) / 10**token_out["rawTokenAmount"]["decimals"])
|
tr["amount_out"] = float(int(token_out["rawTokenAmount"]["tokenAmount"]) / 10**token_out["rawTokenAmount"]["decimals"])
|
||||||
#'amount_out': float(token_outputs[0]['rawTokenAmount']['tokenAmount']) / 10**token_outputs[0]['rawTokenAmount']['decimals'],
|
|
||||||
|
# Store transaction in database
|
||||||
|
if tr["type"] in ["BUY", "SELL"]:
|
||||||
|
is_buy = tr["type"] == "BUY"
|
||||||
|
|
||||||
|
transaction = storage.Transaction(
|
||||||
|
wallet=wallet,
|
||||||
|
transaction_type=tr["type"],
|
||||||
|
symbol_in=tr["token_in"],
|
||||||
|
amount_in=tr["amount_in"] if is_buy else 0,
|
||||||
|
value_in_usd=tr.get("swap_amount_usd", 0) if is_buy else 0,
|
||||||
|
symbol_out=tr["token_out"],
|
||||||
|
amount_out=tr["amount_out"] if not is_buy else 0,
|
||||||
|
value_out_usd=tr.get("swap_amount_usd", 0) if not is_buy else 0,
|
||||||
|
tx_signature=tx_signature
|
||||||
|
)
|
||||||
|
await storage.store_transaction(transaction)
|
||||||
|
|
||||||
if swap_event.get('nativeInput'): # SOL
|
if swap_event.get('nativeInput'): # SOL
|
||||||
token_in = swap_event.get('nativeInput', [])
|
token_in = swap_event.get('nativeInput', [])
|
||||||
@ -202,8 +258,6 @@ def init_app(tr_handler=None):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error loading transaction token data: {str(e)}")
|
logging.error(f"Error loading transaction token data: {str(e)}")
|
||||||
|
|
||||||
wallet = data[0]['feePayer'] # Using feePayer as the wallet address
|
|
||||||
tx_signature = data[0]['signature']
|
|
||||||
|
|
||||||
# ToDo - probably optimize
|
# ToDo - probably optimize
|
||||||
tr['symbol_in'] = await SolanaAPI.SAPI.get_token_metadata_symbol(tr['token_in'])
|
tr['symbol_in'] = await SolanaAPI.SAPI.get_token_metadata_symbol(tr['token_in'])
|
||||||
@ -221,7 +275,21 @@ def init_app(tr_handler=None):
|
|||||||
await utils.telegram_utils.send_telegram_message(notification)
|
await utils.telegram_utils.send_telegram_message(notification)
|
||||||
|
|
||||||
# Store the notified transaction in the database
|
# Store the notified transaction in the database
|
||||||
storage.store_transaction(wallet, "SWAP", tr['symbol_in'] , tr['amount_in'], tr['value_in_USD'], tr['symbol_out'], tr['amount_out'], tr['value_out_USD'],tx_signature)
|
# storage.store_transaction(wallet, "SWAP", tr['symbol_in'] , tr['amount_in'], tr['value_in_USD'], tr['symbol_out'], tr['amount_out'], tr['value_out_USD'],tx_signature)
|
||||||
|
copyTransaction = storage.Transaction(
|
||||||
|
wallet=wallet,
|
||||||
|
transaction_type=tr["type"],
|
||||||
|
symbol_in=tr["token_in"],
|
||||||
|
amount_in=tr["amount_in"] if is_buy else 0,
|
||||||
|
value_in_usd=tr.get("swap_amount_usd", 0) if is_buy else 0,
|
||||||
|
symbol_out=tr["token_out"],
|
||||||
|
amount_out=tr["amount_out"] if not is_buy else 0,
|
||||||
|
value_out_usd=tr.get("swap_amount_usd", 0) if not is_buy else 0,
|
||||||
|
tx_signature=tx_signature
|
||||||
|
)
|
||||||
|
try: storage.store_transaction(copyTransaction)
|
||||||
|
except: logging.error(traceback.format_exc())
|
||||||
|
|
||||||
# Attempt to execute the copytrade transaction
|
# Attempt to execute the copytrade transaction
|
||||||
try:
|
try:
|
||||||
# await SolanaAPI.SAPI.follow_move(tr)
|
# await SolanaAPI.SAPI.follow_move(tr)
|
||||||
@ -242,10 +310,29 @@ def init_app(tr_handler=None):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Error processing transaction notification: {str(e)}")
|
logging.error(f"Error processing transaction notification: {str(e)}")
|
||||||
# Log the full traceback for debugging
|
# Log the full traceback for debugging
|
||||||
import traceback
|
|
||||||
logging.error(traceback.format_exc())
|
logging.error(traceback.format_exc())
|
||||||
|
|
||||||
@app.route('/retry', methods=['GET'])
|
@app.route('/replay_wh', methods=['POST'])
|
||||||
|
async def replay_wh():
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
filename = data.get('filename')
|
||||||
|
if not filename:
|
||||||
|
return jsonify({"error": "Filename not provided"}), 400
|
||||||
|
|
||||||
|
file_path = os.path.join(SolanaAPI.root_path, 'logs', filename)
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return jsonify({"error": "File not found"}), 404
|
||||||
|
|
||||||
|
with open(file_path, 'r') as f:
|
||||||
|
log_data = json.load(f)
|
||||||
|
|
||||||
|
await process_wh(log_data)
|
||||||
|
return jsonify({"status": "Replay successful"}), 200
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error replaying webhook file: {e}")
|
||||||
|
return jsonify({"error": "Failed to replay webhook file"}), 500
|
||||||
@app.route('/retry-last-log', methods=['GET'])
|
@app.route('/retry-last-log', methods=['GET'])
|
||||||
async def retry_last_log():
|
async def retry_last_log():
|
||||||
wh = request.args.get('wh', 'false').lower() == 'true'
|
wh = request.args.get('wh', 'false').lower() == 'true'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user