# middleman_bot.py

import discord
from discord.ext import commands, tasks
from discord.ui import Select, View, Button
import asyncio
import aiohttp
import os
from dotenv import load_dotenv
import sqlite3
from datetime import datetime
from eth_account import Account
from bitcoinlib.wallets import Wallet
from cryptography.fernet import Fernet
from web3 import Web3
import qrcode
from io import BytesIO

# Load environment variables from .env file
load_dotenv()

# ==== Environment Variables ====

# Remove BOT_ETH_ADDRESS and BOT_ETH_PRIVATE_KEY
# Remove BOT_LTC_WALLET_NAME and BOT_LTC_PRIVATE_KEY

DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')

# Litecoin Configuration
BLOCKCYPHER_TOKEN = os.getenv('BLOCKCYPHER_TOKEN')  # For Litecoin

# Ethereum Configuration
ETHERSCAN_TOKEN = os.getenv('ETHERSCAN_TOKEN')      # For Ethereum
INFURA_URL = os.getenv('INFURA_URL')                # Ethereum node URL

# Fee Wallets
FEE_ETH_ADDRESS = os.getenv('FEE_ETH_ADDRESS')      # Predefined Ethereum fee wallet
FEE_LTC_ADDRESS = os.getenv('FEE_LTC_ADDRESS')      # Predefined Litecoin fee wallet

# Encryption Key Path
SECRET_KEY_PATH = os.getenv('SECRET_KEY_PATH', 'secret.key')  # Default to 'secret.key'

# Fee Configuration
FEE_PERCENTAGE = 0.01  # 1%
MIN_FEE_USD = 5        # Minimum fee in USD

# Initialize Web3 for Ethereum
web3 = Web3(Web3.HTTPProvider(INFURA_URL))

# ==== Initialize Discord Bot ====
intents = discord.Intents.default()
intents.message_content = True
intents.guilds = True
intents.members = True
intents.messages = True
intents.reactions = True
intents.presences = False

bot = commands.Bot(command_prefix='!', intents=intents)

# ==== Database Setup ====
def init_db():
    conn = sqlite3.connect('transactions.db')
    c = conn.cursor()
    c.execute('''
        CREATE TABLE IF NOT EXISTS transactions (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            guild_id INTEGER,
            channel_id INTEGER,
            sender_id INTEGER,
            receiver_id INTEGER,
            crypto TEXT,
            amount REAL,
            status TEXT,
            created_at TEXT,
            withdrawal_address TEXT,
            escrow_wallet_address TEXT,
            escrow_private_key TEXT
        )
    ''')
    conn.commit()
    conn.close()

init_db()

# ==== Encryption Setup ====
def generate_key():
    """Generate and save a key"""
    key = Fernet.generate_key()
    with open(SECRET_KEY_PATH, "wb") as key_file:
        key_file.write(key)

def load_key():
    """Load the previously generated key"""
    return open(SECRET_KEY_PATH, "rb").read()

# Uncomment the following line to generate a key (Run only once)
# generate_key()

try:
    fernet = Fernet(load_key())
except FileNotFoundError:
    print("Encryption key not found. Generating a new key.")
    generate_key()
    fernet = Fernet(load_key())

def encrypt_data(data: str) -> str:
    return fernet.encrypt(data.encode()).decode()

def decrypt_data(token: str) -> str:
    return fernet.decrypt(token.encode()).decode()

# ==== Helper Functions ====
def add_transaction(guild_id, channel_id, sender_id, receiver_id, crypto, amount, status='pending', withdrawal_address=None, escrow_wallet_address=None, escrow_private_key=None):
    conn = sqlite3.connect('transactions.db')
    c = conn.cursor()
    c.execute('''
        INSERT INTO transactions (guild_id, channel_id, sender_id, receiver_id, crypto, amount, status, created_at, withdrawal_address, escrow_wallet_address, escrow_private_key)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (
        guild_id,
        channel_id,
        sender_id,
        receiver_id,
        crypto,
        amount,
        status,
        datetime.utcnow().isoformat(),
        withdrawal_address,
        escrow_wallet_address,
        escrow_private_key  # Store encrypted private key
    ))
    conn.commit()
    transaction_id = c.lastrowid
    conn.close()
    return transaction_id

def update_transaction_status(transaction_id, status):
    conn = sqlite3.connect('transactions.db')
    c = conn.cursor()
    c.execute('''
        UPDATE transactions
        SET status = ?
        WHERE id = ?
    ''', (status, transaction_id))
    conn.commit()
    conn.close()

def update_withdrawal_address(transaction_id, address):
    conn = sqlite3.connect('transactions.db')
    c = conn.cursor()
    c.execute('''
        UPDATE transactions
        SET withdrawal_address = ?
        WHERE id = ?
    ''', (address, transaction_id))
    conn.commit()
    conn.close()

def get_transaction_by_channel(channel_id):
    conn = sqlite3.connect('transactions.db')
    c = conn.cursor()
    c.execute('''
        SELECT * FROM transactions
        WHERE channel_id = ?
    ''', (channel_id,))
    row = c.fetchone()
    conn.close()
    return row

# ==== Blockchain API Interaction ====
async def check_payment(crypto, wallet_address, expected_amount):
    if crypto.lower() == 'litecoin':
        # BlockCypher API for Litecoin
        api_url = f'https://api.blockcypher.com/v1/ltc/main/addrs/{wallet_address}/balance?token={BLOCKCYPHER_TOKEN}'
        async with aiohttp.ClientSession() as session:
            async with session.get(api_url) as resp:
                if resp.status != 200:
                    return False
                data = await resp.json()
                balance = data.get('balance', 0) / 1e8  # Convert from litoshis
                return balance >= expected_amount
    elif crypto.lower() == 'ethereum':
        # Etherscan API for Ethereum
        api_url = f'https://api.etherscan.io/api?module=account&action=balance&address={wallet_address}&tag=latest&apikey={ETHERSCAN_TOKEN}'
        async with aiohttp.ClientSession() as session:
            async with session.get(api_url) as resp:
                if resp.status != 200:
                    return False
                data = await resp.json()
                balance = int(data.get('result', 0)) / 1e18  # Convert from wei
                return balance >= expected_amount
    else:
        return False

# ==== Wallet Creation Functions ====
def create_ethereum_wallet():
    acct = Account.create()
    address = acct.address
    private_key = acct.key.hex()
    return address, private_key

def create_litecoin_wallet():
    # Generate a new Litecoin wallet with bitcoinlib
    wallet = Wallet.create(f'TempWallet_{datetime.utcnow().strftime("%Y%m%d%H%M%S")}', network='litecoin')
    address = wallet.get_key().address
    private_key = wallet.get_key().wif
    # Delete the wallet from bitcoinlib's storage if not needed
    wallet.delete()
    return address, private_key

# ==== QR Code Generation Function ====
def generate_qr_code(address):
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4,
    )
    qr.add_data(address)
    qr.make(fit=True)
    
    img = qr.make_image(fill_color="black", back_color="white")
    # Save image to a BytesIO object
    img_io = BytesIO()
    img.save(img_io, 'PNG')
    img_io.seek(0)
    return img_io

# ==== Sending Funds Function ====
async def send_crypto(crypto, amount, receiver_address, fee_address, escrow_wallet_address, escrow_private_key_encrypted):
    """
    Send cryptocurrency to the receiver and fee address using the escrow wallet.
    Returns True if both transactions are successful, False otherwise.
    """
    if crypto.lower() == 'ethereum':
        try:
            # Decrypt the escrow private key
            escrow_private_key = decrypt_data(escrow_private_key_encrypted)

            # Initialize an account object
            escrow_account = web3.eth.account.from_key(escrow_private_key)

            # Prepare transaction to Receiver
            nonce = web3.eth.get_transaction_count(escrow_account.address)
            gas_price = web3.toWei('50', 'gwei')  # Adjust as needed
            tx_receiver = {
                'nonce': nonce,
                'to': receiver_address,
                'value': web3.toWei(amount, 'ether'),
                'gas': 21000,
                'gasPrice': gas_price,
                'chainId': 1  # Mainnet
            }
            
            signed_tx_receiver = escrow_account.sign_transaction(tx_receiver)
            tx_hash_receiver = web3.eth.send_raw_transaction(signed_tx_receiver.rawTransaction)
            receipt_receiver = web3.eth.wait_for_transaction_receipt(tx_hash_receiver)
            if receipt_receiver.status != 1:
                print("Ethereum transaction to receiver failed.")
                return False

            # Prepare transaction to Fee Wallet
            nonce += 1
            fee_amount = FEE_PERCENTAGE * amount
            fee_amount = fee_amount if fee_amount >= (MIN_FEE_USD / get_eth_price()) else (MIN_FEE_USD / get_eth_price())
            tx_fee = {
                'nonce': nonce,
                'to': fee_address,
                'value': web3.toWei(fee_amount, 'ether'),
                'gas': 21000,
                'gasPrice': gas_price,
                'chainId': 1
            }
            
            signed_tx_fee = escrow_account.sign_transaction(tx_fee)
            tx_hash_fee = web3.eth.send_raw_transaction(signed_tx_fee.rawTransaction)
            receipt_fee = web3.eth.wait_for_transaction_receipt(tx_hash_fee)
            if receipt_fee.status != 1:
                print("Ethereum transaction to fee wallet failed.")
                return False

            return True

        except Exception as e:
            print(f"Error sending Ethereum transactions: {e}")
            return False

    elif crypto.lower() == 'litecoin':
        try:
            # Decrypt the escrow private key
            escrow_private_key = decrypt_data(escrow_private_key_encrypted)

            # Initialize a wallet object using the private key
            wallet = Wallet.import_wallet(f'EscrowWallet_{escrow_wallet_address}', keys=escrow_private_key, network='litecoin')

            # Send to Receiver
            tx_receiver = wallet.send_to(receiver_address, amount=amount, fee=10000)  # fee in litoshis
            if not tx_receiver:
                print("Litecoin transaction to receiver failed.")
                wallet.delete()
                return False

            # Send to Fee Wallet
            fee_amount = FEE_PERCENTAGE * amount
            fee_amount = fee_amount if fee_amount >= (MIN_FEE_USD / get_ltc_price()) else (MIN_FEE_USD / get_ltc_price())
            tx_fee = wallet.send_to(fee_address, amount=fee_amount, fee=10000)
            if not tx_fee:
                print("Litecoin transaction to fee wallet failed.")
                wallet.delete()
                return False

            # Delete the wallet after transactions
            wallet.delete()

            return True

        except Exception as e:
            print(f"Error sending Litecoin transactions: {e}")
            return False

    else:
        print(f"Unsupported cryptocurrency: {crypto}")
        return False

def get_eth_price():
    """Fetch current ETH price in USD."""
    async def fetch_price():
        async with aiohttp.ClientSession() as session:
            eth_price_url = "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd"
            async with session.get(eth_price_url) as resp:
                data = await resp.json()
                return data['ethereum']['usd']
    return asyncio.run(fetch_price())

def get_ltc_price():
    """Fetch current LTC price in USD."""
    async def fetch_price():
        async with aiohttp.ClientSession() as session:
            ltc_price_url = "https://api.coingecko.com/api/v3/simple/price?ids=litecoin&vs_currencies=usd"
            async with session.get(ltc_price_url) as resp:
                data = await resp.json()
                return data['litecoin']['usd']
    return asyncio.run(fetch_price())

# ==== Discord UI Components ====
class CryptoSelect(Select):
    def __init__(self):
        options = [
            discord.SelectOption(label="Litecoin (LTC)", value="litecoin"),
            discord.SelectOption(label="Ethereum (ETH)", value="ethereum")
        ]
        super().__init__(placeholder="Choose a cryptocurrency...", min_values=1, max_values=1, options=options)

    async def callback(self, interaction: discord.Interaction):
        selected_crypto = self.values[0]
        await interaction.response.send_message(f'You selected **{selected_crypto.capitalize()}**. Creating a transaction ticket...', ephemeral=True)
        await create_transaction_ticket(interaction, selected_crypto)

class CryptoView(View):
    def __init__(self):
        super().__init__()
        self.add_item(CryptoSelect())

class RoleView(View):
    def __init__(self, transaction_id):
        super().__init__()
        self.transaction_id = transaction_id
        self.sender_button = Button(label="Sender", style=discord.ButtonStyle.primary, custom_id="sender")
        self.receiver_button = Button(label="Receiver", style=discord.ButtonStyle.secondary, custom_id="receiver")
        self.reset_button = Button(label="Reset", style=discord.ButtonStyle.danger, custom_id="reset")

        self.sender_button.callback = self.assign_sender
        self.receiver_button.callback = self.assign_receiver
        self.reset_button.callback = self.reset_roles

        self.add_item(self.sender_button)
        self.add_item(self.receiver_button)
        self.add_item(self.reset_button)

    async def assign_sender(self, interaction: discord.Interaction):
        user = interaction.user
        transaction = get_transaction_by_channel(interaction.channel.id)
        if transaction and transaction[6] == 'roles_pending':  # status == 'roles_pending'
            # Update transaction with sender_id
            conn = sqlite3.connect('transactions.db')
            c = conn.cursor()
            c.execute('''
                UPDATE transactions
                SET sender_id = ?, status = ?
                WHERE id = ?
            ''', (user.id, 'sender_assigned', self.transaction_id))
            conn.commit()
            conn.close()
            await interaction.response.send_message(f"{user.mention} has been assigned as the **Sender**.", ephemeral=True)
            self.sender_button.disabled = True
            await interaction.message.edit(view=self)

    async def assign_receiver(self, interaction: discord.Interaction):
        user = interaction.user
        transaction = get_transaction_by_channel(interaction.channel.id)
        if transaction and transaction[6] == 'roles_pending':  # status == 'roles_pending'
            # Update transaction with receiver_id
            conn = sqlite3.connect('transactions.db')
            c = conn.cursor()
            c.execute('''
                UPDATE transactions
                SET receiver_id = ?, status = ?
                WHERE id = ?
            ''', (user.id, 'receiver_assigned', self.transaction_id))
            conn.commit()
            conn.close()
            await interaction.response.send_message(f"{user.mention} has been assigned as the **Receiver**.", ephemeral=True)
            self.receiver_button.disabled = True
            await interaction.message.edit(view=self)

    async def reset_roles(self, interaction: discord.Interaction):
        transaction = get_transaction_by_channel(interaction.channel.id)
        if transaction:
            # Reset sender_id and receiver_id
            conn = sqlite3.connect('transactions.db')
            c = conn.cursor()
            c.execute('''
                UPDATE transactions
                SET sender_id = ?, receiver_id = ?, status = ?
                WHERE id = ?
            ''', (None, None, 'roles_pending', self.transaction_id))
            conn.commit()
            conn.close()
            await interaction.response.send_message("Roles have been reset.", ephemeral=True)
            self.sender_button.disabled = False
            self.receiver_button.disabled = False
            await interaction.message.edit(view=self)

class ConfirmationView(View):
    def __init__(self, transaction_id):
        super().__init__()
        self.transaction_id = transaction_id
        self.correct_button = Button(label="Confirm", style=discord.ButtonStyle.green, custom_id="confirm")
        self.cancel_button = Button(label="Cancel", style=discord.ButtonStyle.red, custom_id="cancel")

        self.correct_button.callback = self.confirm_correct
        self.cancel_button.callback = self.confirm_cancel

        self.add_item(self.correct_button)
        self.add_item(self.cancel_button)

    async def confirm_correct(self, interaction: discord.Interaction):
        transaction = get_transaction_by_channel(interaction.channel.id)
        if transaction and transaction[6] in ['sender_assigned', 'receiver_assigned']:
            update_transaction_status(transaction[0], 'confirmed')
            await interaction.response.send_message("Transaction details confirmed. Waiting for payment...", ephemeral=True)

    async def confirm_cancel(self, interaction: discord.Interaction):
        transaction = get_transaction_by_channel(interaction.channel.id)
        if transaction:
            update_transaction_status(transaction[0], 'cancelled')
            await interaction.response.send_message("Transaction has been cancelled.", ephemeral=True)
            await interaction.channel.delete()

# ==== Release Funds View ====
class ReleaseFundsView(View):
    def __init__(self, transaction_id, crypto, amount, receiver_address, fee_address, escrow_wallet_address, escrow_private_key_encrypted):
        super().__init__(timeout=None)  # No timeout
        self.transaction_id = transaction_id
        self.crypto = crypto
        self.amount = amount
        self.receiver_address = receiver_address
        self.fee_address = fee_address
        self.escrow_wallet_address = escrow_wallet_address
        self.escrow_private_key_encrypted = escrow_private_key_encrypted

        # Add Release Funds Button
        self.release_button = Button(label="Release Funds", style=discord.ButtonStyle.green, custom_id="release_funds")
        self.release_button.callback = self.release_funds

        self.add_item(self.release_button)

    async def release_funds(self, interaction: discord.Interaction):
        # Check if the user has the required role
        allowed_roles = ['Admin', 'Transaction Starter']  # Update with your actual role names
        if not any(role.name in allowed_roles for role in interaction.user.roles):
            await interaction.response.send_message("You do not have permission to release funds.", ephemeral=True)
            return

        # Release the funds
        success = await send_crypto(
            crypto=self.crypto,
            amount=self.amount,
            receiver_address=self.receiver_address,
            fee_address=self.fee_address,
            escrow_wallet_address=self.escrow_wallet_address,
            escrow_private_key_encrypted=self.escrow_private_key_encrypted
        )

        if success:
            update_transaction_status(self.transaction_id, 'funds_released')
            await interaction.response.send_message("Funds have been successfully released!", ephemeral=True)
            # Optionally, update the channel with a message
            channel = interaction.channel
            await channel.send(f"Funds of **{self.amount:.6f} {self.crypto.upper()}** have been sent to `<@{self.receiver_id}>` and fees to the fee wallet.")
            # Disable the button after use
            self.release_button.disabled = True
            await interaction.message.edit(view=self)
        else:
            await interaction.response.send_message("Failed to release funds. Please try again later.", ephemeral=True)

# ==== Confirmation View Updates ====
# Optionally, after confirmation, you could add the Release Funds button immediately
# Modify the `confirm_correct` method in ConfirmationView to add the ReleaseFundsView

# ==== Core Functions ====
async def create_transaction_ticket(interaction, crypto):
    guild = interaction.guild
    user = interaction.user

    # Check if user has the required role
    allowed_roles = ['Transaction Starter']  # Replace with your actual role names
    if not any(role.name in allowed_roles for role in user.roles):
        await interaction.response.send_message("You do not have permission to start transactions.", ephemeral=True)
        return

    # Create a new private text channel
    overwrites = {
        guild.default_role: discord.PermissionOverwrite(read_messages=False),
        user: discord.PermissionOverwrite(read_messages=True, send_messages=True)
    }

    category = discord.utils.get(guild.categories, name="Transactions")
    if not category:
        category = await guild.create_category("Transactions")

    channel = await guild.create_text_channel(f'transaction-{user.name}', overwrites=overwrites, category=category)

    # Generate unique escrow wallet
    if crypto.lower() == 'ethereum':
        escrow_wallet_address, escrow_private_key = create_ethereum_wallet()
    elif crypto.lower() == 'litecoin':
        escrow_wallet_address, escrow_private_key = create_litecoin_wallet()
    else:
        await channel.send("Unsupported cryptocurrency selected.")
        return

    # Encrypt the escrow_private_key before storing
    escrow_private_key_encrypted = encrypt_data(escrow_private_key)

    # Generate QR code for escrow wallet
    qr_image = generate_qr_code(escrow_wallet_address)

    # Save image to a BytesIO object
    img_io = BytesIO()
    qr_image.save(img_io, 'PNG')
    img_io.seek(0)

    # Embed with QR Code
    embed = discord.Embed(
        title=f"{crypto.capitalize()} Transaction",
        description=f"Scan the QR code below to send **{crypto.upper()}** to the escrow wallet.\n\n**Escrow Address:** `{escrow_wallet_address}`",
        color=0x00ff00
    )
    embed.set_image(url="attachment://qr.png")

    # Send embed with QR code
    file = discord.File(img_io, filename='qr.png')
    await channel.send(file=file, embed=embed)

    # Initialize transaction in the database with escrow_private_key
    transaction_id = add_transaction(
        guild_id=guild.id,
        channel_id=channel.id,
        sender_id=user.id,
        receiver_id=None,
        crypto=crypto,
        amount=0.0,
        status='roles_pending',
        escrow_wallet_address=escrow_wallet_address,
        escrow_private_key=escrow_private_key_encrypted
    )

    # Send role assignment buttons
    role_embed = discord.Embed(
        title="Assign Roles",
        description="Click the buttons below to assign roles as Sender or Receiver.",
        color=0x00ff00
    )
    view = RoleView(transaction_id)
    await channel.send(embed=role_embed, view=view)

async def proceed_to_payment_setup(channel, transaction):
    # Prompt Sender to enter amount and receiver
    embed = discord.Embed(
        title="Transaction Details",
        description="Please enter the receiver's username and the amount to transact in the format:\n`@Username Amount`",
        color=0x00ff00
    )
    await channel.send(embed=embed)

    def check(m):
        return m.channel == channel and m.author.id == transaction[3]  # Sender ID

    try:
        msg = await bot.wait_for('message', check=check, timeout=300)  # 5 minutes
        parts = msg.content.strip().split()
        if len(parts) != 2:
            await channel.send("Invalid format. Please enter as `@Username Amount`.")
            return
        receiver = msg.mentions[0]
        amount_usd = float(parts[1])
        if amount_usd <= 0:
            await channel.send("Amount must be greater than zero.")
            return

        # Fetch latest prices to convert USD to crypto
        eth_price = await fetch_price('ethereum')
        ltc_price = await fetch_price('litecoin')

        # Determine crypto amount based on selected crypto
        crypto = transaction[4].lower()
        if crypto == 'ethereum':
            crypto_amount = amount_usd / eth_price
        elif crypto == 'litecoin':
            crypto_amount = amount_usd / ltc_price
        else:
            await channel.send("Unsupported cryptocurrency selected.")
            return

        # Check if amount meets minimal escrow requirement
        if crypto == 'ethereum' and (crypto_amount * eth_price) < MIN_FEE_USD:
            await channel.send(f"The minimal escrow amount for {crypto.upper()} is **${MIN_FEE_USD} USD**. Please enter a higher amount.")
            return
        if crypto == 'litecoin' and (crypto_amount * ltc_price) < MIN_FEE_USD:
            await channel.send(f"The minimal escrow amount for {crypto.upper()} is **${MIN_FEE_USD} USD**. Please enter a higher amount.")
            return

        # Update transaction in DB
        conn = sqlite3.connect('transactions.db')
        c = conn.cursor()
        c.execute('''
            UPDATE transactions
            SET receiver_id = ?, amount = ?
            WHERE channel_id = ?
        ''', (receiver.id, crypto_amount, channel.id))
        conn.commit()
        conn.close()

        # Confirm details
        embed = discord.Embed(
            title="Confirm Transaction",
            description=f"**Sender:** <@{transaction[3]}>\n"
                        f"**Receiver:** <@{receiver.id}>\n"
                        f"**Crypto:** {crypto.capitalize()}\n"
                        f"**Amount:** {crypto_amount:.6f} {crypto.upper()} (${amount_usd} USD)\n"
                        f"**Minimal Escrow:** ${MIN_FEE_USD} USD",
            color=0x00ff00
        )
        view = ConfirmationView(transaction[0])
        await channel.send(embed=embed, view=view)

    except asyncio.TimeoutError:
        await channel.send("Transaction setup timed out. Please start again.")

async def fetch_price(crypto):
    """Fetch current price for the given cryptocurrency."""
    async with aiohttp.ClientSession() as session:
        price_url = f"https://api.coingecko.com/api/v3/simple/price?ids={crypto}&vs_currencies=usd"
        async with session.get(price_url) as resp:
            data = await resp.json()
            return data[crypto]['usd']

# ==== Background Task to Monitor Payments ====
@tasks.loop(minutes=1)
async def monitor_payments():
    conn = sqlite3.connect('transactions.db')
    c = conn.cursor()
    c.execute('''
        SELECT * FROM transactions
        WHERE status = 'confirmed'
    ''')
    transactions = c.fetchall()
    conn.close()

    for tx in transactions:
        transaction_id = tx[0]
        guild_id = tx[1]
        channel_id = tx[2]
        crypto = tx[4]
        amount = tx[5]
        withdrawal_address = tx[8]
        escrow_wallet_address = tx[9]
        escrow_private_key_encrypted = tx[10]

        # Check if funds have been deposited to escrow
        payment_received = await check_payment(crypto, escrow_wallet_address, amount)
        if payment_received:
            # Update transaction status
            update_transaction_status(transaction_id, 'payment_received')

            # Notify users about payment received
            guild = bot.get_guild(guild_id)
            if not guild:
                print(f"Guild ID {guild_id} not found.")
                continue
            channel = guild.get_channel(channel_id)
            if not channel:
                print(f"Channel ID {channel_id} not found.")
                continue
            sender = guild.get_member(tx[3])  # Sender ID
            receiver = guild.get_member(tx[4])  # Receiver ID

            await channel.send(f"Payment of **{amount:.6f} {crypto.upper()}** received in escrow.")

            # Add Release Funds button
            release_view = ReleaseFundsView(
                transaction_id=transaction_id,
                crypto=crypto,
                amount=amount,
                receiver_address=withdrawal_address,
                fee_address=FEE_ETH_ADDRESS if crypto.lower() == 'ethereum' else FEE_LTC_ADDRESS,
                escrow_wallet_address=escrow_wallet_address,
                escrow_private_key_encrypted=escrow_private_key_encrypted
            )

            await channel.send("Authorized users can now release the funds using the button below.", view=release_view)

# ==== Event Handlers ====
@bot.event
async def on_ready():
    print(f'Logged in as {bot.user}')
    monitor_payments.start()

@bot.command(name='start')
async def start_transaction(ctx):
    # Check if user has the required role
    allowed_roles = ['Transaction Starter']  # Replace with your actual role names
    if not any(role.name in allowed_roles for role in ctx.author.roles):
        await ctx.send("You do not have permission to start transactions.")
        return

    embed = discord.Embed(
        title="Start a Transaction",
        description="Select the cryptocurrency you want to use for the transaction.",
        color=0x00ff00
    )
    view = CryptoView()
    await ctx.send(embed=embed, view=view)

# ==== Run the Bot ====
bot.run(DISCORD_TOKEN) Ok so I want my you not use dot env and I want you to make it so anything under 50 usd is free anything 50 to 200 is a 2 dollar fee and anything past 200  is 1% also I want an option to who will be covering the fees so like if they bot choose and agree on the reviver taking the fee it will just give them the fee and sends it to l the fee wallets and gives them the rest and if the person it will add that on to their total, also this should work flawlessly and you should give me a little explentation how everything works you should give me all the code and make it so it can work with multiple people selling the money and if the bot was to be closed it should regain all the functionalityy and never have a timeout and the buttons can be pressed their should be an admin role command only that they can run to see how much each button release goes and to who and to what person and if they do h they can set it off with a command so like /release if: this Gould all be slash commands with emebeds and make it all work perfectly