# 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 ====
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')

# Litecoin Configuration
BLOCKCYPHER_TOKEN = os.getenv('BLOCKCYPHER_TOKEN')  # For Litecoin
BOT_LTC_WALLET_NAME = os.getenv('BOT_LTC_WALLET_NAME')  # Name for the Litecoin wallet in bitcoinlib
BOT_LTC_PRIVATE_KEY = os.getenv('BOT_LTC_PRIVATE_KEY')  # Bot's Litecoin private key

# Ethereum Configuration
ETHERSCAN_TOKEN = os.getenv('ETHERSCAN_TOKEN')      # For Ethereum
INFURA_URL = os.getenv('INFURA_URL')                # Ethereum node URL
BOT_ETH_ADDRESS = os.getenv('BOT_ETH_ADDRESS')      # Bot's Ethereum address
BOT_ETH_PRIVATE_KEY = os.getenv('BOT_ETH_PRIVATE_KEY')  # Bot's Ethereum private key

# 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
        )
    ''')
    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):
    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)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (
        guild_id,
        channel_id,
        sender_id,
        receiver_id,
        crypto,
        amount,
        status,
        datetime.utcnow().isoformat(),
        withdrawal_address,
        escrow_wallet_address
    ))
    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
    # Optionally, 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):
    """
    Send cryptocurrency to the receiver and fee address.
    Returns True if both transactions are successful, False otherwise.
    """
    if crypto.lower() == 'ethereum':
        try:
            # Prepare transaction to Receiver
            nonce = web3.eth.get_transaction_count(BOT_ETH_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 = web3.eth.account.sign_transaction(tx_receiver, private_key=BOT_ETH_PRIVATE_KEY)
            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
            tx_fee = {
                'nonce': nonce,
                'to': fee_address,
                'value': web3.toWei(FEE_PERCENTAGE * amount if FEE_PERCENTAGE * amount > MIN_FEE_USD else MIN_FEE_USD, 'ether'),
                'gas': 21000,
                'gasPrice': gas_price,
                'chainId': 1
            }
            
            signed_tx_fee = web3.eth.account.sign_transaction(tx_fee, private_key=BOT_ETH_PRIVATE_KEY)
            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:
            # Initialize bot's Litecoin wallet
            wallet = Wallet.get(BOT_LTC_WALLET_NAME)
            # 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.")
                return False

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

            return True

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

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

# ==== 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', transaction[0]))
            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', transaction[0]))
            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', transaction[0]))
            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="Correct", style=discord.ButtonStyle.green, custom_id="correct")
        self.disagree_button = Button(label="Disagree", style=discord.ButtonStyle.red, custom_id="disagree")

        self.correct_button.callback = self.confirm_correct
        self.disagree_button.callback = self.confirm_disagree

        self.add_item(self.correct_button)
        self.add_item(self.disagree_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. Proceeding...", ephemeral=True)
            await proceed_to_payment_setup(interaction.channel, transaction)

    async def confirm_disagree(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], 'disputed')
            await interaction.response.send_message("Transaction details disputed. Please reset the transaction.", ephemeral=True)

# ==== 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

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

    # Save QR code image temporarily
    img_filename = f'qr_{channel.id}.png'
    with open(img_filename, 'wb') as f:
        f.write(qr_image.read())

    # 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.",
        color=0x00ff00
    )
    embed.set_thumbnail(url=f"attachment://{img_filename}")

    # Send embed with QR code
    file = discord.File(img_filename, filename=img_filename)
    await channel.send(file=file, embed=embed)

    # Initialize transaction in the database
    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
    )

    # 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)

    # Clean up the temporary QR code image
    os.remove(img_filename)

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
        async with aiohttp.ClientSession() as session:
            # Fetch ETH price
            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:
                eth_data = await resp.json()
                eth_price = eth_data['ethereum']['usd']

            # Fetch LTC price
            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:
                ltc_data = await resp.json()
                ltc_price = ltc_data['litecoin']['usd']

        # 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_amount * eth_price < MIN_FEE_USD and crypto == 'ethereum':
            await channel.send(f"The minimal escrow amount for {crypto.upper()} is **${MIN_FEE_USD} USD**. Please enter a higher amount.")
            return
        if crypto_amount * ltc_price < MIN_FEE_USD and crypto == 'litecoin':
            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.")

# ==== 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]

        # 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)
            channel = guild.get_channel(channel_id)
            receiver = guild.get_member(tx[4])  # Receiver ID

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

            # Request Withdrawal Address via DM
            if receiver:
                try:
                    dm_channel = await receiver.create_dm()
                    await dm_channel.send(
                        f"You have received **{amount:.6f} {crypto.upper()}**! Please reply to this message with your withdrawal wallet address to receive the funds."
                    )

                    def dm_check(m):
                        return m.author == receiver and isinstance(m.channel, discord.DMChannel)

                    try:
                        dm_msg = await bot.wait_for('message', check=dm_check, timeout=300)  # 5 minutes
                        receiver_wallet = dm_msg.content.strip()

                        # Validate the wallet address format here
                        if crypto.lower() == 'ethereum':
                            if not Web3.isAddress(receiver_wallet):
                                await dm_channel.send("Invalid Ethereum address format. Transaction canceled.")
                                update_transaction_status(transaction_id, 'failed')
                                await channel.send(f"Transaction failed due to invalid Receiver address.")
                                continue

                        elif crypto.lower() == 'litecoin':
                            # Simple validation: starts with 'L' or 'M' and is 34 characters long
                            if not (receiver_wallet.startswith('L') or receiver_wallet.startswith('M')) or len(receiver_wallet) != 34:
                                await dm_channel.send("Invalid Litecoin address format. Transaction canceled.")
                                update_transaction_status(transaction_id, 'failed')
                                await channel.send(f"Transaction failed due to invalid Receiver address.")
                                continue

                        else:
                            await dm_channel.send("Unsupported cryptocurrency.")
                            update_transaction_status(transaction_id, 'failed')
                            await channel.send(f"Transaction failed due to unsupported cryptocurrency.")
                            continue

                        # Update transaction with withdrawal address
                        update_withdrawal_address(transaction_id, receiver_wallet)

                        # Calculate fee
                        fee_usd = MAX(FEE_PERCENTAGE * (amount * (5 / 5)), MIN_FEE_USD) if crypto.lower() == 'ethereum' else MAX(FEE_PERCENTAGE * (amount * (5 / 5)), MIN_FEE_USD)
                        fee = FEE_PERCENTAGE * amount if crypto.lower() == 'ethereum' else FEE_PERCENTAGE * amount
                        if fee < MIN_FEE_USD:
                            fee = MIN_FEE_USD

                        amount_to_receiver = amount - fee

                        # Prevent negative or zero transfers
                        if amount_to_receiver <= 0:
                            await dm_channel.send("Transaction amount is too low after deducting the fee. Transaction canceled.")
                            update_transaction_status(transaction_id, 'failed')
                            await channel.send(f"Transaction failed due to insufficient amount after fee deduction.")
                            continue

                        # Determine fee wallet based on crypto
                        fee_wallet = FEE_ETH_ADDRESS if crypto.lower() == 'ethereum' else FEE_LTC_ADDRESS

                        # Send funds to Receiver and Fee Wallet
                        send_success = await send_crypto(crypto, amount_to_receiver, receiver_wallet, fee_wallet)

                        if send_success:
                            update_transaction_status(transaction_id, 'funds_released')
                            await channel.send(f"Funds successfully sent to <@{receiver.id}> at address `{receiver_wallet}` minus fee of **{fee:.6f} {crypto.upper()}**.")
                            await dm_channel.send(f"Your funds of **{amount_to_receiver:.6f} {crypto.upper()}** have been sent to your wallet address `{receiver_wallet}`.")
                        else:
                            update_transaction_status(transaction_id, 'failed')
                            await channel.send(f"Failed to send funds to <@{receiver.id}>. Please try again later.")
                            await dm_channel.send("There was an error processing your withdrawal. Please contact support.")

                    except asyncio.TimeoutError:
                        await dm_channel.send("You did not reply in time. Transaction canceled.")
                        update_transaction_status(transaction_id, 'failed')
                        await channel.send(f"Transaction failed due to no response from Receiver.")

                except Exception as e:
                    print(f"Error sending DM to receiver: {e}")
                    await channel.send("Could not send DM to Receiver. Creating a support ticket instead.")
                    # Create a support ticket channel
                    support_channel = await guild.create_text_channel(f'support-{receiver.name}', overwrites={
                        guild.default_role: discord.PermissionOverwrite(read_messages=False),
                        receiver: discord.PermissionOverwrite(read_messages=True),
                        guild.me: discord.PermissionOverwrite(read_messages=True)
                    })
                    await support_channel.send(f"<@{receiver.id}>, please provide your withdrawal wallet address here to complete the transaction.")
                    update_transaction_status(transaction_id, 'awaiting_withdrawal_address')

    # ==== 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)
 Alright I want you to add some code and give me the whole code it should make a new wallet for each eth and ltc payment so there’s no bot ltc account or eth account aprt from the fee wallets can you code this for me?