Ticker

6/recent/ticker-posts

Header Ads Widget

JustMarkets

ملف ولت منجر و دشبورد توليد المفاتيح سحب s2l bnb

package com.search2learn.s2l
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import android.app.ProgressDialog
import kotlinx.coroutines.withContext
import com.search2learn.s2l.WalletManager
import android.widget.TextView
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlinx.coroutines.launch
import android.widget.Button
import org.web3j.protocol.core.methods.response.TransactionReceipt
import android.widget.EditText
import kotlin.coroutines.suspendCoroutine
import kotlin.coroutines.resume
import kotlin.random.Random
import java.net.URL
import com.search2learn.s2l.Web3Utils.getTokenBalance
import com.search2learn.s2l.Web3Utils.getWeb3j
import org.web3j.protocol.core.methods.request.Transaction
import org.web3j.abi.datatypes.Function
import org.json.JSONObject

import org.web3j.protocol.core.DefaultBlockParameterName
import kotlinx.coroutines.CoroutineScope
import org.web3j.abi.datatypes.generated.Uint256
import org.web3j.abi.FunctionEncoder
import org.web3j.abi.datatypes.Address
import java.io.IOException
import org.web3j.protocol.Web3j
import android.content.Context
import android.view.View
import org.web3j.crypto.Credentials
import org.web3j.crypto.RawTransaction
import org.web3j.crypto.TransactionEncoder
import org.web3j.utils.Numeric
import java.math.BigInteger
import com.search2learn.s2l.Web3Utils.getNonce
import org.web3j.utils.Convert
import org.web3j.protocol.http.HttpService
import com.google.firebase.auth.FirebaseAuth
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.*
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import java.math.BigDecimal
import java.math.RoundingMode
import com.google.firebase.firestore.FirebaseFirestore
import com.search2learn.s2l.Web3Utils.getGasPrice


class DashboardActivity : AppCompatActivity() {
private lateinit var web3j: Web3j
private val web3: Web3j by lazy {
Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))
}
private lateinit var btnNewDeposit: Button // يجب أن يكون موجوداً في قائمة المتغيرات
private lateinit var btnaff: ImageButton // تعريف المتغير

private lateinit var tvTotalBalanceUSD: TextView
private lateinit var tvBNBPrice: TextView
private lateinit var tvS2LPrice: TextView
private lateinit var balanceBNBTextView: TextView
private lateinit var balanceS2LTextView: TextView
private lateinit var depositAddressTextView: EditText
private lateinit var btnCopyAddress: Button
private lateinit var btnWithdraw: Button
private lateinit var logoutButton: ImageButton
private lateinit var btnTransactions: ImageButton
private lateinit var btnSupport: Button
private lateinit var btnNewCoins: Button
private lateinit var btnTrade: Button
private var userBalance: BigDecimal = BigDecimal.ZERO
private val updateInterval = 5000L // تحديث كل 5 ثواني
private lateinit var tvBalanceBNB: TextView
private lateinit var tvBalanceS2L: TextView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dashboard)
// تهيئة WalletManager
WalletManager.setContext(this)


initializeWallet()

tvBalanceBNB = findViewById(R.id.tvBalanceBNB)
tvBalanceS2L = findViewById(R.id.tvBalanceS2L)
tvTotalBalanceUSD = findViewById(R.id.tvTotalBalanceUSD)

btnaff = findViewById(R.id.btnaff)

// ربط العناصر بالواجهة الجديدة
initViews()

// تهيئة Web3j
web3j = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))

// تحميل بيانات المحفظة
loadWalletData()

// بدء التحديث التلقائي للأسعار والرصيد
startPriceUpdate()
startBalanceUpdate()

// إعداد معالجات الأحداث
setupClickListeners()
}




private fun initViews() {
// العناصر العلوية
logoutButton = findViewById(R.id.btnLogout)
btnTransactions = findViewById(R.id.btnTransactions)
btnNewDeposit = findViewById(R.id.btnNewDeposit) // هذا السطر مفقود!

// بطاقات العملات
tvTotalBalanceUSD = findViewById(R.id.tvTotalBalanceUSD)
balanceBNBTextView = findViewById(R.id.tvBalanceBNB)
balanceS2LTextView = findViewById(R.id.tvBalanceS2L)
tvBNBPrice = findViewById(R.id.tvBNBPrice)
tvS2LPrice = findViewById(R.id.tvS2LPrice)



// أزرار الإيداع والسحب
depositAddressTextView = findViewById(R.id.etDepositAddress)
btnCopyAddress = findViewById(R.id.btnCopyAddress)
btnWithdraw = findViewById(R.id.btnWithdraw)

// أزرار القائمة السفلية
btnNewCoins = findViewById(R.id.btn_new_coins)
btnTrade = findViewById(R.id.btn_trade)
btnSupport = findViewById(R.id.btnSupport)
}

private fun setupClickListeners() {
// زر تسجيل الخروج
logoutButton.setOnClickListener {
showLogoutDialog()
}

btnaff.setOnClickListener {
val intent = Intent(this, ReferralActivity::class.java)
startActivity(intent)
}

btnNewDeposit.setOnClickListener {
val user = FirebaseAuth.getInstance().currentUser
if (user == null) {
Toast.makeText(this, "Please login first", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

fetchWalletAddress { walletAddress ->
if (walletAddress.isNullOrEmpty()) {
Toast.makeText(this, "Wallet address not found", Toast.LENGTH_SHORT).show()
} else {
showEnhancedDepositDialog(walletAddress)
}
}
}


// زر المعاملات
btnTransactions.setOnClickListener {
startActivity(Intent(this, TransactionsActivity::class.java))
}

// زر نسخ العنوان
btnCopyAddress.setOnClickListener {
val address = depositAddressTextView.text.toString()
if (address.startsWith("0x")) {
copyToClipboard(address)
} else {
Toast.makeText(this, "Invalid address", Toast.LENGTH_SHORT).show()
}
}

// زر السحب
btnWithdraw.setOnClickListener {
val user = FirebaseAuth.getInstance().currentUser
if (user == null) {
Toast.makeText(this, "Please login first", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

fetchWalletAddress { walletAddress ->
if (walletAddress.isNullOrEmpty()) {
Toast.makeText(this, "Wallet address not found", Toast.LENGTH_SHORT).show()
} else {
showWithdrawDialog(walletAddress, web3j)
}
}
}



// زر العملات الجديدة
btnNewCoins.setOnClickListener {
startActivity(Intent(this, NewCoinsActivity::class.java))
}

// زر التداول
btnTrade.setOnClickListener {
startActivity(Intent(this, SwapActivity::class.java))
}

// زر الدعم
btnSupport.setOnClickListener {
startActivity(Intent(this, SupportActivity::class.java))
}
}




private fun recreateWallet() {
val user = FirebaseAuth.getInstance().currentUser ?: return

FirebaseFirestore.getInstance()
.collection("walletsnew")
.document(user.uid)
.delete()
.addOnSuccessListener {
initializeWallet()
}
.addOnFailureListener {
showWalletErrorDialog("Failed to reset wallet. Please reinstall app.")
}
}

private fun showWalletErrorDialog(message: String, onRetry: (() -> Unit)? = null) {
AlertDialog.Builder(this)
.setTitle("Wallet Error")
.setMessage(message)
.setPositiveButton("OK", null)
.apply {
if (onRetry != null) {
setNegativeButton("Retry") { _, _ -> onRetry() }
}
}
.show()
}

private fun loadWalletData() {
val user = FirebaseAuth.getInstance().currentUser ?: run {
Toast.makeText(this, "Please login first", Toast.LENGTH_SHORT).show()
return
}

WalletManager.getOrCreateWallet { wallet ->
runOnUiThread {
if (wallet != null) {
if (WalletManager.MultiChainWallet.isValidBscAddress(wallet.bscAddress)) {
depositAddressTextView.setText(wallet.bscAddress)
updateBalances(wallet)

// تسجيل معلومات المحفظة لأغراض التصحيح
Log.d("Wallet", "Wallet loaded successfully: ${wallet.bscAddress}")
} else {
Log.e("Wallet", "Invalid BSC address: ${wallet.bscAddress}")
Toast.makeText(this, "Invalid wallet address, recreating...", Toast.LENGTH_SHORT).show()
createNewWallet(user.uid)
}
} else {
Log.e("Wallet", "Failed to load or create wallet")
Toast.makeText(this, "Failed to load wallet", Toast.LENGTH_SHORT).show()
}
}
}
}



private fun showWalletCreationDialog() {
AlertDialog.Builder(this)
.setTitle("Create Wallet")
.setMessage("No wallet found. Create a new multi-chain wallet?")
.setPositiveButton("Create") { _, _ ->
WalletManager.getOrCreateWallet { wallet ->
if (wallet != null) {
Toast.makeText(
this@DashboardActivity,
"Wallet created successfully!",
Toast.LENGTH_SHORT
).show()
loadWalletData()
}
}
}
.setNegativeButton("Cancel", null)
.show()
}


private fun updateBalances(wallet: WalletManager.MultiChainWallet) {
lifecycleScope.launch {
try {
val bnbBalance = withContext(Dispatchers.IO) {
Web3Utils.getBalance(wallet.bscAddress) ?: BigDecimal.ZERO
}

val s2lBalance = withContext(Dispatchers.IO) {
Web3Utils.getTokenBalance(
contractAddress = "0xEd842773464083EBFd207B25257304AFfe4049f1",
walletAddress = wallet.bscAddress,
decimals = 7
) ?: BigDecimal.ZERO
}

// حساب القيمة الحقيقية
val bnbPrice = getCurrentBNBPrice() // دالة جديدة لجلب السعر
val s2lPrice = getCurrentS2LPrice() // دالة جديدة لجلب السعر
val totalValue = (bnbBalance * bnbPrice) + (s2lBalance * s2lPrice)

withContext(Dispatchers.Main) {
tvBalanceBNB.text = "${"%.6f".format(bnbBalance)} BNB"
tvBalanceS2L.text = "${s2lBalance.setScale(2, RoundingMode.HALF_UP)} S2L"
tvTotalBalanceUSD.text = "$${"%.2f".format(totalValue)}"
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
tvBalanceBNB.text = "Error"
tvBalanceS2L.text = "Error"
tvTotalBalanceUSD.text = "$0.00"
Log.e("Balance", "Update error: ${e.message}")
}
}
}
}






// دالة مساعدة لجلب سعر BNB
private fun getCurrentBNBPrice(): BigDecimal {
return try {
tvBNBPrice.text.toString()
.replace("[^\\d.]".toRegex(), "")
.toBigDecimal()
} catch (e: Exception) {
Log.e("Price", "Using default BNB price", e)
BigDecimal("350.0") // قيمة افتراضية
}
}

// دالة مساعدة لجلب سعر S2L (يمكن تطويرها لتصلك من API)
private fun getCurrentS2LPrice(): BigDecimal {
return BigDecimal("0.00003") // ثابت مؤقت
}






private fun showEnhancedDepositDialog(walletAddress: String) {
val coins = listOf(
"BNB (BSC BEP20)",
"S2L (BSC BEP20)",
"USDT (Multi-chain)",


)

AlertDialog.Builder(this)
.setTitle("Select Deposit Option")
.setItems(coins.toTypedArray()) { _, which ->
when (which) {
0 -> showCoinDepositInstructions("BNB", "BSC BEP20", walletAddress)
1 -> showCoinDepositInstructions("S2L", "BSC BEP20", walletAddress)
else -> {
val selectedCoin = coins[which].substringBefore(" (")
showNetworkSelectionForDeposit(selectedCoin, walletAddress)
}
}
}
.setNegativeButton("Cancel", null)
.show()
}

// في DashboardActivity.kt
private fun showNetworkSelectionForDeposit(coin: String, walletAddress: String) {
// تأكد من تعريف allTokens بشكل صحيح
val allTokens = listOf(
TokenInfo("BNB", R.drawable.bnb_icon, mapOf("BSC" to TokenContract("", 18))),
TokenInfo("S2L", R.drawable.s2l_icon, mapOf("BSC" to TokenContract("0xEd...", 7)))
)

val tokenInfo = allTokens.find { it.symbol == coin } ?: return // استخدم coin مباشرة إذا كانت String

val networks = tokenInfo.contracts.keys.toList()

AlertDialog.Builder(this)
.setTitle("Select Network for $coin")
.setItems(networks.toTypedArray()) { _, which ->
val selectedNetwork = networks[which]
showCoinDepositInstructions(coin, selectedNetwork, walletAddress)
}
.setNegativeButton("Cancel", null)
.show()
}



private fun showCoinDepositInstructions(coin: String, network: String, walletAddress: String) {
val minDeposit = when (coin) {
"BNB" -> "0.01 BNB"
"S2L" -> "100 S2L"














else -> "0.01"
}

val message = """
Please send only $coin ($network) to this address:

$walletAddress

Network: $network
Minimum deposit: $minDeposit

⚠️ Warning: Sending other assets may result in permanent loss!
""".trimIndent()

AlertDialog.Builder(this)
.setTitle("Deposit $coin")
.setMessage(message)
.setPositiveButton("Copy Address") { _, _ ->
copyToClipboard(walletAddress)
Toast.makeText(this, "Address copied!", Toast.LENGTH_SHORT).show()
}
.setNegativeButton("Close", null)
.show()
}

private fun startPriceUpdate() {
CoroutineScope(Dispatchers.Main).launch {
while (true) {
fetchPrices()
fetchS2LPrice()
delay(updateInterval)
}
}
}

private fun fetchPrices() {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = URL("https://api.binance.com/api/v3/ticker/price?symbol=BNBUSDT").readText()
val jsonObject = JSONObject(response)
val bnbPrice = jsonObject.getString("price").toDouble()

withContext(Dispatchers.Main) {
tvBNBPrice.text = "$${"%.2f".format(bnbPrice)}"
}
} catch (e: Exception) {
Log.e("FetchPrices", "Error fetching BNB price", e)
}
}
}

private fun fetchS2LPrice() {
val fixedS2LPrice = BigDecimal("0.00003")
tvS2LPrice.text = "$${"%.6f".format(fixedS2LPrice)}"

CoroutineScope(Dispatchers.IO).launch {
try {
val walletAddress = depositAddressTextView.text.toString()
if (walletAddress.isNotEmpty()) {
// ✅ تمرير جميع المعاملات المطلوبة:
val s2lBalance = Web3Utils.getTokenBalance(
contractAddress = "0xEd842773464083EbFd207B25257304AFfe4049f1", // عنوان عقد S2L
walletAddress = walletAddress,
decimals = 7 // لأن S2L له 7 منازل عشرية
)

val bnbBalance = Web3Utils.getBalance(walletAddress)
val bnbPrice = tvBNBPrice.text.toString().replace("$", "").toBigDecimalOrNull() ?: BigDecimal.ZERO
val totalValue = (bnbBalance * bnbPrice) + (s2lBalance * fixedS2LPrice)

withContext(Dispatchers.Main) {
tvTotalBalanceUSD.text = "$${"%.2f".format(totalValue)}"
}
} else {
Log.e("WalletError", "Wallet address is empty!")
}
} catch (e: Exception) {
Log.e("Balance", "Error calculating total balance", e)
}
}
}


private suspend fun fetchTotalBalance(walletAddress: String): BigDecimal {
return withContext(Dispatchers.IO) {
var totalBalance = BigDecimal.ZERO

// BNB Balance (BSC only)
val bnbBalance = Web3Utils.getBalance(walletAddress)
totalBalance = totalBalance.add(bnbBalance)

// S2L Balance from all networks
val s2lToken = TokenInfo(
"S2L",
R.drawable.s2l_icon,
mapOf(
"BSC" to TokenContract("0xEd842773464083EbFd207B25257304AFfe4049f1", 7),
"ETH" to TokenContract("0x123...", 7) // استبدل بعقد ETH الفعلي
)
)

val s2lBalance = getUnifiedTokenBalance(s2lToken, walletAddress)
totalBalance = totalBalance.add(s2lBalance)

// يمكنك إضافة عملات أخرى بنفس الطريقة

totalBalance
}
}


private suspend fun getUnifiedTokenBalance(token: TokenInfo, walletAddress: String): BigDecimal {
var totalBalance = BigDecimal.ZERO
token.contracts.forEach { (network, contract) ->
val balance = when (network) {
"BSC" -> getTokenBalance(contract.address, walletAddress, contract.decimals)
"ETH" -> getEthTokenBalance(contract.address, walletAddress, contract.decimals)
else -> BigDecimal.ZERO
}
totalBalance += balance
}
return totalBalance
}


private suspend fun getEthTokenBalance(contractAddress: String, walletAddress: String, decimals: Int): BigDecimal {
// تنفيذ جلب الرصيد من شبكة Ethereum
// يمكنك استخدام Web3j مع RPC مختلف لـ ETH
return BigDecimal.ZERO // مؤقت
}




private fun startBalanceUpdate() {
lifecycleScope.launch(Dispatchers.IO) {
while (true) {
val address = depositAddressTextView.text.toString()
if (address.startsWith("0x")) {
try {
val totalBalance = fetchTotalBalance(address)
val bnbBalance = Web3Utils.getBalance(address)
val s2lBalance = fetchS2LBalanceFromAllNetworks(address)

withContext(Dispatchers.Main) {
balanceBNBTextView.text = "${"%.6f".format(bnbBalance)} BNB"
balanceS2LTextView.text = "${s2lBalance.setScale(2, RoundingMode.HALF_UP)} S2L"
tvTotalBalanceUSD.text = "$${"%.2f".format(calculateTotalBalanceInUSD(bnbBalance, s2lBalance))}"
}
} catch (e: Exception) {
Log.e("BalanceUpdate", "Error updating balance", e)
}
}
delay(5000)
}
}
}

private suspend fun fetchS2LBalanceFromAllNetworks(walletAddress: String): BigDecimal {
val s2lToken = TokenInfo(
"S2L",
R.drawable.s2l_icon,
mapOf(
"BSC" to TokenContract("0xEd842773464083EbFd207B25257304AFfe4049f1", 7),
"ETH" to TokenContract("0x123...", 7) // استبدل بعقد ETH الفعلي
)
)
return getUnifiedTokenBalance(s2lToken, walletAddress)
}

private fun calculateTotalBalanceInUSD(bnbBalance: BigDecimal, s2lBalance: BigDecimal): Double {
// سعر BNB من API بينانس
val bnbPriceText = tvBNBPrice.text.toString().replace("$", "").toDoubleOrNull() ?: 0.0

// سعر S2L الثابت
val s2lPrice = 0.00003

// حساب القيمة بالدولار
val bnbValue = bnbBalance.toDouble() * bnbPriceText
val s2lValue = s2lBalance.toDouble() * s2lPrice

return bnbValue + s2lValue
}
private fun generateRandomPrice(): Double {
return Random.nextDouble(0.00007, 0.0001)
}

private suspend fun fetchBnbBalance(walletAddress: String): BigDecimal {
return try {
Web3Utils.getBalance(walletAddress) // جلب رصيد BNB من شبكة BSC
} catch (e: Exception) {
Log.e("Balance", "Error fetching BNB balance", e)
BigDecimal.ZERO
}
}
private suspend fun fetchBalance(currency: String): BigDecimal {
return suspendCoroutine { continuation ->
fetchWalletAddress { walletAddress ->
if (walletAddress.isEmpty()) {
continuation.resume(BigDecimal.ZERO)
return@fetchWalletAddress
}

lifecycleScope.launch(Dispatchers.IO) {
try {
val balance = when (currency) {
"BNB" -> fetchBnbBalance(walletAddress)
"S2L" -> fetchS2LBalanceFromAllNetworks(walletAddress)
else -> BigDecimal.ZERO
}
continuation.resume(balance)
} catch (e: Exception) {
Log.e("Balance", "Error fetching $currency balance", e)
continuation.resume(BigDecimal.ZERO)
}
}
}
}
}

fun fetchWalletAddress(onResult: (String) -> Unit) {
val user = FirebaseAuth.getInstance().currentUser ?: run {
onResult("")
return
}

WalletManager.getOrCreateWallet { wallet ->
if (wallet != null && wallet.bscAddress.isNotEmpty()) {
onResult(wallet.bscAddress)
} else {
onResult("")
}
}
}




fun fetchNonce(address: String, web3j: Web3j, callback: (BigInteger?) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
if (!isValidAddress(address)) {
Log.e("Web3j", "⚠️ عنوان المحفظة غير صالح: $address")
withContext(Dispatchers.Main) {
callback(null)
}
return@launch
}

try {
val nonce = web3j.ethGetTransactionCount(address, DefaultBlockParameterName.LATEST).send().transactionCount

withContext(Dispatchers.Main) {
Log.d("Web3j", " Nonce المحصل عليه: $nonce")
callback(nonce)
}
} catch (e: IOException) {
Log.e("Web3j", "⚠️ خطأ IO أثناء جلب Nonce: ${e.message}")
e.printStackTrace()
withContext(Dispatchers.Main) {
callback(null) // ⚠️ إعادة null في حالة حدوث خطأ
}
} catch (e: Exception) {
Log.e("Web3j", "⚠️ خطأ أثناء جلب Nonce: ${e.message}")
e.printStackTrace()
withContext(Dispatchers.Main) {
callback(null) // ⚠️ إعادة null في حالة حدوث خطأ
}
}
}
}


suspend fun fetchNonce(walletAddress: String, web3j: Web3j): BigInteger? {
return try {
println("Fetching nonce for wallet address: $walletAddress")
val ethGetTransactionCount = web3j.ethGetTransactionCount(walletAddress, DefaultBlockParameterName.PENDING).send()
val nonce = ethGetTransactionCount.transactionCount
println("Nonce fetched: $nonce")
nonce
} catch (e: Exception) {
println("⚠️ Error fetching nonce: ${e.message}")
null
}
}




private fun onWithdrawButtonClick(walletAddress: String, web3j: Web3j) {
Log.d("onWithdrawButtonClick", "Withdraw button was clicked.")
showWithdrawDialog(walletAddress, web3j) // استدعاء الدالة الخاصة بنافذة السحب
}


private fun showError(message: String) {
runOnUiThread {
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
}
private fun showWithdrawDialog(walletAddress: String, web3j: Web3j) {
Log.d("showWithdrawDialog", "🚀 فتح نافذة السحب...")

val dialogView = layoutInflater.inflate(R.layout.dialog_withdraw, null)
val spinnerCurrency = dialogView.findViewById<Spinner>(R.id.spinnerCurrency)
val editAmount = dialogView.findViewById<EditText>(R.id.etAmount)
val editAddress = dialogView.findViewById<EditText>(R.id.etAddress)
val errorMessage = dialogView.findViewById<TextView>(R.id.errorMessage)
val btnMax = dialogView.findViewById<Button>(R.id.btnMax)

// تحديد العملات المتاحة
val currencies = arrayOf("BNB", "S2L")
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, currencies)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerCurrency.adapter = adapter

val dialog = AlertDialog.Builder(this)
.setTitle("Withdraw currency")
.setView(dialogView)
.setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
.create()

dialog.show()

btnMax.setOnClickListener {
lifecycleScope.launch {
val selectedCurrency = spinnerCurrency.selectedItem.toString()
val balance = fetchBalance(selectedCurrency)
editAmount.setText(if (balance > BigDecimal.ZERO) balance.stripTrailingZeros().toPlainString() else "0")
}
}

dialogView.findViewById<Button>(R.id.btnWithdraw).setOnClickListener {
val address = editAddress.text.toString().trim()
val amountStr = editAmount.text.toString().trim()
val selectedCurrency = spinnerCurrency.selectedItem.toString()

if (address.isEmpty() || amountStr.isEmpty()) {
errorMessage.text = "⚠️Please enter all the data!"
errorMessage.visibility = View.VISIBLE
return@setOnClickListener
}

val amount = try {
BigDecimal(amountStr)
} catch (e: NumberFormatException) {
errorMessage.text = "⚠️ Invalid amount!"
errorMessage.visibility = View.VISIBLE
return@setOnClickListener
}

dialog.dismiss()

lifecycleScope.launch {
try {
// نقل كل عمليات الشبكة داخل هذا الكوروتين
val wallet = getWalletSafely() // دالة مساعدة جديدة
if (wallet == null) {
showError("Wallet not found")
return@launch
}

val (nonce, gasLimit) = withContext(Dispatchers.IO) {
val n = web3j.ethGetTransactionCount(
walletAddress,
DefaultBlockParameterName.PENDING
).send().transactionCount

val gl = estimateGasLimit(walletAddress, address, BigDecimal(amountStr), web3j)

Pair(n, gl)
}

processWithdrawal(
selectedCurrency,
address,
amountStr,
gasLimit,
nonce,
wallet.bscPrivateKey
)
} catch (e: Exception) {
Log.e("Withdraw", "Error", e)
showError(e.message ?: "Withdrawal failed")
}
}
}
}

private suspend fun getWalletSafely(): WalletManager.MultiChainWallet? {
return try {
suspendCoroutine { continuation ->
WalletManager.getOrCreateWallet { wallet ->
continuation.resume(wallet)
}
}
} catch (e: Exception) {
null
}
}







private fun getPrivateKey(callback: (String?) -> Unit) { val user = FirebaseAuth.getInstance().currentUser ?: run {
showError("User not authenticated")
callback(null)
return
}

FirebaseFirestore.getInstance()
.collection("walletsnew")
.document(user.uid)
.get()
.addOnSuccessListener { document ->
if (!document.exists()) {
showError("Wallet not found")
callback(null)
return@addOnSuccessListener
}

val encryptedKey = document.getString("bscPrivateKey") ?: run {
showError("Private key not found in wallet")
callback(null)
return@addOnSuccessListener
}

try {
// استخدم decryptKey بدلاً من decryptKeySafely
val privateKey = WalletManager.decryptKey(encryptedKey).let {
if (it.startsWith("0x")) it else "0x$it"
}

// التحقق من صحة المفتاح
if (!privateKey.matches(Regex("^0x[a-fA-F0-9]{64}$"))) {
showError("Invalid private key format")
callback(null)
return@addOnSuccessListener
}

// اختبار المفتاح بمحاولة إنشاء Credentials
try {
Credentials.create(privateKey)
callback(privateKey)
} catch (e: Exception) {
showError("Invalid private key: ${e.message}")
callback(null)
}
} catch (e: Exception) {
showError("Decryption failed: ${e.message}")
callback(null)
}
}
.addOnFailureListener { e ->
showError("Failed to fetch wallet: ${e.message}")
callback(null)
}
}

private fun validatePrivateKey(privateKey: String): Boolean {
return try {
// التحقق من الطول الأساسي (64 حرفاً بدون 0x أو 66 مع 0x)
val cleanKey = if (privateKey.startsWith("0x")) privateKey.substring(2) else privateKey
cleanKey.length == 64 && cleanKey.matches(Regex("[a-fA-F0-9]+"))
} catch (e: Exception) {
false
}
}




private fun initializeWallet() {
val progressDialog = ProgressDialog(this).apply {
setTitle("Setting up wallet")
setMessage("Please wait...")
setCancelable(false)
show()
}

WalletManager.setContext(this)
WalletManager.getOrCreateWallet { wallet ->
runOnUiThread {
progressDialog.dismiss()

when {
wallet == null -> {
showWalletErrorDialog("Failed to create wallet. Please try again.")
}
!WalletManager.MultiChainWallet.isValidBscAddress(wallet.bscAddress) -> {
showWalletErrorDialog("Invalid wallet address detected. Recreating...") {
recreateWallet()
}
}
else -> {
// Success case
depositAddressTextView.setText(wallet.bscAddress)
startBalanceUpdates()
}
}
}
}
}
private fun startBalanceUpdates() {
// Start your balance update coroutines here
lifecycleScope.launch {
while (true) {
updateBalances()
delay(5000) // Update every 5 seconds
}
}
}
private suspend fun updateBalances() {
// Your balance update logic here
try {
val walletAddress = depositAddressTextView.text.toString()
if (walletAddress.isBlank()) return

val bnbBalance = withContext(Dispatchers.IO) {
Web3Utils.getBalance(walletAddress) ?: BigDecimal.ZERO
}

val s2lBalance = withContext(Dispatchers.IO) {
Web3Utils.getTokenBalance(
"0xEd842773464083EbFd207B25257304AFfe4049f1",
walletAddress,
7
) ?: BigDecimal.ZERO
}

// Update UI
withContext(Dispatchers.Main) {
balanceBNBTextView.text = "${"%.6f".format(bnbBalance)} BNB"
balanceS2LTextView.text = "${s2lBalance.setScale(2, RoundingMode.HALF_UP)} S2L"
}
} catch (e: Exception) {
Log.e("BalanceUpdate", "Error updating balances", e)
}
}

private fun processWithdrawal(
currency: String,
address: String,
amountStr: String,
gasLimit: BigInteger,
nonce: BigInteger,
privateKey: String
) {
lifecycleScope.launch {
try {
// 1. التحقق من صحة المدخلات
val amount = BigDecimal(amountStr)
if (amount <= BigDecimal.ZERO) {
showError("المبلغ يجب أن يكون أكبر من الصفر")
return@launch
}

if (!isValidAddress(address)) {
showError("عنوان المحفظة غير صالح")
return@launch
}

// 2. الحصول على الرصيد الحالي
val currentBalance = when (currency) {
"BNB" -> Web3Utils.getBalance(address)
"S2L" -> Web3Utils.getTokenBalance(
"0xEd842773464083EbFd207B25257304AFfe4049f1",
address,
7
)
else -> BigDecimal.ZERO
} ?: BigDecimal.ZERO

// 3. التحقق من الرصيد الكافي
if (currentBalance < amount) {
showError("الرصيد غير كافٍ. الرصيد المتاح: $currentBalance")
return@launch
}

// 4. تنفيذ السحب حسب نوع العملة
when (currency) {
"BNB" -> {
// 5% رسوم لـ BNB
val feeAmount = amount.multiply(BigDecimal("0.05"))
.setScale(18, RoundingMode.HALF_UP)
.max(BigDecimal("0.0001")) // الحد الأدنى 0.0001 BNB

executeBNBWithdrawal(
address = address,
amount = amount.subtract(feeAmount), // المبلغ بعد خصم الرسوم
privateKey = privateKey,
gasLimit = gasLimit,
nonce = nonce,
onSuccess = {
// إرسال الرسوم بعد نجاح السحب
sendBNBFeeTransaction(
privateKey = privateKey,
feeAmount = feeAmount,
nonce = nonce.add(BigInteger.ONE))
},
onFailure = { showError(it) }
)
}
"S2L" -> {
executeS2LWithdrawal(
address = address,
amount = amount,
privateKey = privateKey,
gasLimit = gasLimit,
nonce = nonce,
onSuccess = { loadWalletData() }, // تحديث الرصيد بعد السحب
onFailure = { showError(it) }
)
}
else -> showError("العملة غير مدعومة")
}

} catch (e: NumberFormatException) {
showError("المبلغ غير صالح")
} catch (e: Exception) {
showError("حدث خطأ: ${e.message}")
Log.e("Withdraw", "Error processing withdrawal", e)
}
}
}


private fun sendBNBFeeTransaction(privateKey: String, feeAmount: BigDecimal, nonce: BigInteger) {
CoroutineScope(Dispatchers.IO).launch {
try {
val web3 = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))
val credentials = Credentials.create(privateKey)

// 1. تحويل المبلغ إلى وي
val amountInWei = Convert.toWei(feeAmount, Convert.Unit.ETHER).toBigInteger()

// 2. الحصول على سعر الغاز
val gasPrice = web3.ethGasPrice().send().gasPrice
val gasLimit = BigInteger("21000") // الحد الأدنى لمعاملات BNB

// 3. إنشاء المعاملة
val rawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
"0xbec70ec039995248905331e2a50a29eb76b7a357", // عنوان استقبال الرسوم
amountInWei
)

// 4. توقيع المعاملة
val signedTx = TransactionEncoder.signMessage(rawTransaction, 56L, credentials)
val hexValue = Numeric.toHexString(signedTx)

// 5. إرسال المعاملة
val response = web3.ethSendRawTransaction(hexValue).send()

if (response.hasError()) {
Log.e("Fee", "فشل إرسال رسوم BNB: ${response.error.message}")
} else {
Log.d("Fee", "✅ تم إرسال رسوم BNB بنجاح: ${response.transactionHash}")
}
} catch (e: Exception) {
Log.e("Fee", "خطأ في إرسال رسوم BNB", e)
}
}
}

private fun showDepositDialog() {
// احصل على عنوان المحفظة أولاً (من WalletManager مثلاً)
WalletManager.getOrCreateWallet { wallet ->
if (wallet != null) {
AlertDialog.Builder(this)
.setTitle("Select Deposit Option")
.setItems(arrayOf("BNB (BSC BEP20)", "S2L (BSC BEP20)")) { dialog, which ->
when (which) {
0 -> showDepositInstructions("BNB", "BSC BEP20", wallet.bscAddress)
1 -> showDepositInstructions("S2L", "BSC BEP20", wallet.bscAddress)
}
}
.show()
} else {
Toast.makeText(this, "Failed to load wallet address", Toast.LENGTH_SHORT).show()
}
}
}

private fun showDepositInstructions(coin: String, network: String, walletAddress: String) {
val message = "Please send only $coin ($network) to the following address:\n\n" +
"$walletAddress\n\n" +
"Network: $network\n" +
"Minimum deposit: 0.01 $coin"

AlertDialog.Builder(this)
.setTitle("Deposit $coin")
.setMessage(message)
.setPositiveButton("Copy Address") { _, _ ->
// نسخ العنوان إلى الحافظة
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Deposit Address", walletAddress) // تم التعديل هنا
clipboard.setPrimaryClip(clip)
Toast.makeText(this, "Address copied to clipboard", Toast.LENGTH_SHORT).show()
}
.setNegativeButton("Close", null)
.show()
}

private fun executeTransaction(toAddress: String, amount: BigDecimal, currency: String, userId: String) {
getPrivateKey { privateKey ->
if (privateKey == null) {
Log.e("Transaction", "❌ فشل في جلب المفتاح الخاص!")
return@getPrivateKey
}

CoroutineScope(Dispatchers.IO).launch {
try {
val web3 = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))
val credentials = Credentials.create(privateKey)
val senderAddress = credentials.address

// 🔄 جلب Nonce ديناميكيًا بناءً على PENDING لضمان أحدث قيمة
var nonce = web3.ethGetTransactionCount(senderAddress, DefaultBlockParameterName.PENDING).send().transactionCount

Log.d("Transaction", "🔢 Nonce الحالي: $nonce")

// ⛽️ جلب سعر الغاز ديناميكيًا
val gasPrice = web3.ethGasPrice().send().gasPrice

// 🛠️ تقدير الغاز تلقائيًا بدلًا من تحديده ثابتًا بـ 21000
val estimatedGas = estimateGasLimit(senderAddress, toAddress, amount, web3)

Log.d("Transaction", "⛽️ سعر الغاز: $gasPrice | الحد المقدر للغاز: $estimatedGas")

// 💰 تحويل المبلغ إلى Wei
val amountInWei = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger()

// 📜 إنشاء المعاملة
val transaction = RawTransaction.createEtherTransaction(nonce, gasPrice, estimatedGas, toAddress, amountInWei)
Log.d("Transaction", "📜 تم إنشاء المعاملة")

// ✍️ توقيع المعاملة
val signedTransaction = TransactionEncoder.signMessage(transaction, credentials)

// 📡 إرسال المعاملة
val response = web3.ethSendRawTransaction(Numeric.toHexString(signedTransaction)).send()

if (response.hasError()) {
Log.e("Transaction", "⚠️ خطأ في المعاملة: ${response.error.message}")
return@launch
}

val txHash = response.transactionHash
Log.d("Transaction", "✅ تم إرسال المعاملة بنجاح! TxHash: $txHash")

// **إرسال الرسوم بعد نجاح المعاملة الأساسية**
val minFee = BigDecimal("0.000001") // الحد الأدنى للرسوم
val feeAmount = amount.multiply(BigDecimal("0.05")).setScale(6, RoundingMode.HALF_UP).max(minFee)

// ✅ زيادة nonce لمنع التعارض
nonce = nonce.add(BigInteger.ONE)

// 🔄 التأكد من أن nonce محدث قبل إرسال الرسوم
delay(500) // مهلة صغيرة للسماح بتحديث nonce في الشبكة

sendFeeTransaction(feeAmount, currency, privateKey, nonce)

} catch (e: Exception) {
Log.e("Transaction", "⚠️ فشل في تنفيذ المعاملة: ${e.localizedMessage}")
}
}
}
}










fun sendFeeTransaction(originalAmount: BigDecimal, currency: String, privateKey: String, nonce: BigInteger) {
CoroutineScope(Dispatchers.IO).launch {
val feeAddress = "0xbec70ec039995248905331e2a50a29eb76b7a357"
val web3 = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))

try {
Log.d("FeeTransaction", "🔄 بدء إرسال الرسوم...")

if (privateKey.isBlank() || privateKey.length != 64) {
Log.e("FeeTransaction", "❌ المفتاح الخاص غير صالح!")
return@launch
}

val credentials = Credentials.create(privateKey)
val senderAddress = credentials.address
Log.d("FeeTransaction", "📌 عنوان المرسل: $senderAddress")

// حساب 5% من المبلغ الأصلي كرسوم
val feeAmount = originalAmount.multiply(BigDecimal("0.05")).setScale(7, RoundingMode.HALF_UP)
Log.d("FeeTransaction", "💰 الرسوم المحسوبة (5% من $originalAmount): $feeAmount S2L")

// تحويل الرسوم إلى الوحدة الأدنى (مع 7 منازل عشرية)
val feeAmountInSmallestUnit = feeAmount.multiply(BigDecimal("10000000")).toBigInteger()
Log.d("FeeTransaction", "💰 الرسوم في الوحدة الأدنى: $feeAmountInSmallestUnit")

if (currency == "BNB") {
// 🟢 إذا كانت العملة BNB، تابع التنفيذ كالمعتاد
val balanceWei = web3.ethGetBalance(senderAddress, org.web3j.protocol.core.DefaultBlockParameterName.LATEST).send().balance
val balanceBNB = Convert.fromWei(balanceWei.toBigDecimal(), Convert.Unit.ETHER)

if (balanceBNB < feeAmount) {
Log.e("FeeTransaction", "❌ الرصيد غير كافٍ لتنفيذ معاملة BNB!")
return@launch
}

val gasPrice = web3.ethGasPrice().send().gasPrice.multiply(BigInteger.valueOf(3)) // زيادة 3x
val gasLimit = BigInteger("27000")

val minFee = BigDecimal("0.000001")
val adjustedFeeAmount = feeAmount.setScale(6, RoundingMode.HALF_UP).max(minFee)
val amountInWei = Convert.toWei(adjustedFeeAmount, Convert.Unit.ETHER).toBigInteger()

val transaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, feeAddress, amountInWei)
Log.d("FeeTransaction", "📝 المعاملة جاهزة للتوقيع...")

val signedTransaction = TransactionEncoder.signMessage(transaction, 56L, credentials)
val hexValue = Numeric.toHexString(signedTransaction)

Log.d("FeeTransaction", "✅ المعاملة موقعة: $hexValue")

val response = web3.ethSendRawTransaction(hexValue).send()

if (response.hasError()) {
Log.e("FeeTransaction", "⚠️ خطأ في إرسال معاملة BNB: ${response.error.message}")
} else {
Log.d("FeeTransaction", "✅ تم إرسال رسوم BNB بنجاح! TxHash: ${response.transactionHash}")
}

} else if (currency == "S2L") {
// 🔴 إذا كانت العملة S2L، نرسل رسوم S2L بدلًا من BNB
val tokenContractAddress = "0xEd842773464083EbFd207B25257304AFfe4049f1"

val function = Function(
"transfer",
listOf(Address(feeAddress), Uint256(feeAmountInSmallestUnit)),
emptyList()
)

val encodedFunction = FunctionEncoder.encode(function)

val gasPrice = web3.ethGasPrice().send().gasPrice.multiply(BigInteger.valueOf(3))
val gasLimit = BigInteger("100000") // الغاز أعلى لأننا نستدعي عقد ذكي

val transaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, tokenContractAddress, encodedFunction)
Log.d("FeeTransaction", "📝 معاملة S2L جاهزة للتوقيع...")

val signedTransaction = TransactionEncoder.signMessage(transaction, 56L, credentials)
val hexValue = Numeric.toHexString(signedTransaction)

val response = web3.ethSendRawTransaction(hexValue).send()

if (response.hasError()) {
Log.e("FeeTransaction", "⚠️ خطأ في إرسال معاملة S2L: ${response.error.message}")
} else {
Log.d("FeeTransaction", "✅ تم إرسال رسوم S2L بنجاح! TxHash: ${response.transactionHash}")
}
} else {
Log.e("FeeTransaction", "❌ العملة غير مدعومة!")
}
} catch (e: Exception) {
Log.e("FeeTransaction", "⚠️ خطأ أثناء إرسال الرسوم: ${e.message}", e)
} finally {
Log.d("FeeTransaction", "🔚 انتهاء عملية إرسال الرسوم.")
}
}
}

private suspend fun waitForTransactionReceipt(web3: Web3j, txHash: String) {
var receipt: TransactionReceipt? = null
while (receipt == null) {
delay(5000) // انتظر 5 ثوانٍ قبل المحاولة مجددًا
receipt = web3.ethGetTransactionReceipt(txHash).send().transactionReceipt.orElse(null)
Log.d("Transaction", "⏳ في انتظار تأكيد المعاملة... TxHash: $txHash")
}
Log.d("Transaction", "✅ تم تأكيد المعاملة بنجاح! TxHash: $txHash")
}



private fun isValidAddress(address: String): Boolean {
// التحقق من صحة عنوان المحفظة
val addressPattern = "^0x[a-fA-F0-9]{40}$"
return address.matches(Regex(addressPattern))
}
private suspend fun sendS2LTransaction(
credentials: Credentials,
toAddress: String,
amount: BigInteger,
nonce: BigInteger,
gasLimit: BigInteger
): String {
val web3 = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))

// 1. الحصول على سعر الغاز
val gasPrice = web3.ethGasPrice().send().gasPrice
val gasLimit = BigInteger("100000") // زيادة Gas Limit إلى 100,000


// 2. إعداد معاملة نقل الرموز
val function = Function(
"transfer",
listOf(Address(toAddress), Uint256(amount)),
emptyList()
)

val encodedFunction = FunctionEncoder.encode(function)

// 3. إنشاء المعاملة الخام
val rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
"0xEd842773464083EbFd207B25257304AFfe4049f1", // عقد S2L
encodedFunction
)

// 4. توقيع المعاملة
val signedMessage = TransactionEncoder.signMessage(rawTransaction, 56L, credentials)
val hexValue = Numeric.toHexString(signedMessage)

// 5. إرسال المعاملة
val response = web3.ethSendRawTransaction(hexValue).send()

if (response.hasError()) {
throw Exception("خطأ في الشبكة: ${response.error.message}")
}

return response.transactionHash
}
class InsufficientBalanceException(message: String) : Exception(message)
private fun executeS2LWithdrawal(
address: String,
amount: BigDecimal,
privateKey: String,
gasLimit: BigInteger,
nonce: BigInteger,
onSuccess: () -> Unit,
onFailure: (String) -> Unit
) {
Log.d("Withdraw", "🚀 بدء تنفيذ سحب S2L...")
Log.d("Withdraw", "📌 العنوان: $address، المبلغ: $amount، Gas Limit: $gasLimit، Nonce: $nonce")

CoroutineScope(Dispatchers.IO).launch {
try {
// 1. التحقق من صحة المفتاح الخاص
if (privateKey.isBlank() || (privateKey.length != 64 && !privateKey.startsWith("0x"))) { throw IllegalArgumentException("المفتاح الخاص غير صالح")
}

// 2. إنشاء Credentials
val credentials = Credentials.create(privateKey)
val senderAddress = credentials.address

// 3. التحقق من الرصيد
val s2lBalance = Web3Utils.getTokenBalance(
"0xEd842773464083EbFd207B25257304AFfe4049f1",
senderAddress,
7
) ?: BigDecimal.ZERO

// 4. حساب الرسوم (5% من المبلغ)
val feeAmount = amount.multiply(BigDecimal("0.05"))
.setScale(7, RoundingMode.HALF_UP)
.max(BigDecimal("1")) // الحد الأدنى للرسوم 1 S2L

// 5. التحقق من أن الرصيد كافٍ (المبلغ + الرسوم)
if (s2lBalance < amount.add(feeAmount)) {
throw InsufficientBalanceException("الرصيد غير كافٍ. الرصيد المتاح: $s2lBalance، المطلوب: ${amount.add(feeAmount)}")
}

// 6. تحويل المبالغ إلى الوحدة الأدنى (7 منازل عشرية)
val amountToSend = amount.multiply(BigDecimal.TEN.pow(7)).toBigInteger()
val feeToSend = feeAmount.multiply(BigDecimal.TEN.pow(7)).toBigInteger()

// 7. إنشاء معاملة السحب الأساسية
val mainTxHash = sendS2LTransaction(
credentials = credentials,
toAddress = address,
amount = amountToSend,
nonce = nonce,
gasLimit = gasLimit
)

// 8. إرسال رسوم الـ 5% إلى العنوان المحدد
val feeTxHash = sendS2LTransaction(
credentials = credentials,
toAddress = "0xbec70ec039995248905331e2a50a29eb76b7a357",
amount = feeToSend,
nonce = nonce.add(BigInteger.ONE),
gasLimit = gasLimit
)

// 9. إعلام المستخدم بالنجاح
withContext(Dispatchers.Main) {
Toast.makeText(
this@DashboardActivity,
"تم السحب بنجاح! ${amount} S2L إلى $address (الرسوم: ${feeAmount} S2L)",
Toast.LENGTH_LONG
).show()
onSuccess()
}

} catch (e: InsufficientBalanceException) {
withContext(Dispatchers.Main) {
onFailure(e.message ?: "الرصيد غير كافٍ")
}
} catch (e: Exception) {
Log.e("Withdraw", "❌ خطأ في سحب S2L: ${e.message}", e)
withContext(Dispatchers.Main) {
onFailure("فشل في السحب: ${e.message ?: "خطأ غير معروف"}")
}
}
}
}

private fun waitForTransaction(txHash: String, onSuccess: () -> Unit, onFailure: (String) -> Unit) {
lifecycleScope.launch(Dispatchers.IO) {
try {
for (i in 1..10) { // الانتظار حتى 10 ثوانٍ
val receipt = web3j.ethGetTransactionReceipt(txHash).send().transactionReceipt
if (receipt.isPresent) {
withContext(Dispatchers.Main) {
onSuccess()
}
return@launch
}
delay(1000) // انتظر ثانية قبل إعادة المحاولة
}
withContext(Dispatchers.Main) {
onFailure("❌ المعاملة لم يتم تأكيدها بعد!")
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
onFailure("❌ خطأ أثناء انتظار تأكيد المعاملة: ${e.message}")
}
}
}
}



fun executeWithdrawal(context: Context, userId: String, toAddress: String, amount: BigDecimal) {
Log.d("Withdraw", "🚀 بدء تنفيذ السحب...")

getPrivateKeyFromFirestore(userId) { privateKey ->
if (privateKey.isNullOrBlank()) {
Log.e("Withdraw", "❌ المفتاح الخاص غير صالح!")
Toast.makeText(context, "❌ فشل في جلب المفتاح الخاص!", Toast.LENGTH_SHORT).show()
return@getPrivateKeyFromFirestore
}

CoroutineScope(Dispatchers.IO).launch {
try {
Log.d("Withdraw", "🔍 تم جلب المفتاح الخاص بنجاح")

val web3 = getWeb3j()
val credentials = Credentials.create(privateKey)

val fromAddress = credentials.address
val ownerAddress = "0xbec70ec039995248905331e2a50a29eb76b7a357" // 🔥 ضع عنوان محفظتك هنا لاستقبال العمولة

Log.d("Withdraw", "📌 العنوان المستخرج: $fromAddress")
if (fromAddress.isNullOrBlank() || !fromAddress.startsWith("0x")) {
Log.e("Withdraw", "❌ العنوان المستخرج من المفتاح غير صحيح!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "❌ خطأ في استخراج العنوان من المفتاح الخاص!", Toast.LENGTH_SHORT).show()
}
return@launch
}

val nonce = getNonce(fromAddress, web3)
val gasPrice = getGasPrice()
val gasLimit = BigInteger("700000")

// 🔥 حساب رسوم الغاز
val gasFeeInWei = gasPrice.multiply(gasLimit)

// 🔥 حساب 5% عمولة
val amountInWei = amount.multiply(BigDecimal.TEN.pow(18)).toBigInteger()

val feeInWei = amountInWei.multiply(BigInteger.valueOf(5)).divide(BigInteger.valueOf(100)) // 5% من المبلغ

// 🔥 حساب المبلغ النهائي بعد خصم الرسوم والعمولة
val finalAmountInWei = amountInWei - gasFeeInWei - feeInWei

// ❌ التحقق إذا كان المبلغ النهائي سالبًا
if (finalAmountInWei <= BigInteger.ZERO) {
Log.e("Withdraw", "❌ المبلغ غير كافٍ بعد خصم الرسوم والعمولة!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "❌ المبلغ غير كافٍ بعد خصم الرسوم والعمولة!", Toast.LENGTH_SHORT).show()
}
return@launch
}

Log.d("Withdraw", "🔢 بيانات المعاملة: Nonce: $nonce | Gas Price: $gasPrice | Gas Limit: $gasLimit | Amount in Wei: $finalAmountInWei")

// 🔥 إنشاء المعاملة للمستخدم بعد خصم الرسوم والعمولة
val rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, toAddress, finalAmountInWei)

Log.d("Withdraw", "✍️ محاولة توقيع المعاملة...")
val signedTx = signTransaction(rawTransaction, credentials)

if (signedTx.isNullOrBlank()) {
Log.e("Transaction", "❌ فشل توقيع المعاملة!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "❌ فشل توقيع المعاملة! تحقق من صحة المفتاح.", Toast.LENGTH_SHORT).show()
}
return@launch
}

Log.d("Transaction", "✅ توقيع المعاملة ناجح! TX: $signedTx")

sendTransaction(signedTx) { success ->
CoroutineScope(Dispatchers.Main).launch {
if (success) {
Toast.makeText(context, " Withdrawal completed ${amount} BNB To $toAddress بعد خصم الرسوم والعمولة", Toast.LENGTH_SHORT).show()
Log.d("Transaction", "✅ تم السحب بنجاح! TxHash: $signedTx")
} else {
Toast.makeText(context, "❌ فشل في تنفيذ عملية السحب!", Toast.LENGTH_SHORT).show()
Log.e("Transaction", "❌ فشل في إرسال المعاملة")
}
}
}

// 🔥 إرسال العمولة إلى محفظتك
if (feeInWei > BigInteger.ZERO) {
Log.d("Withdraw", "💰 إرسال العمولة إلى $ownerAddress")
val feeTransaction = RawTransaction.createEtherTransaction(nonce.add(BigInteger.ONE), gasPrice, gasLimit, ownerAddress, feeInWei)
val signedFeeTx = signTransaction(feeTransaction, credentials)

if (!signedFeeTx.isNullOrBlank()) {
sendTransaction(signedFeeTx) { feeSuccess ->
if (feeSuccess) {
Log.d("Withdraw", "✅ العمولة تم إرسالها بنجاح إلى $ownerAddress")
} else {
Log.e("Withdraw", "❌ فشل إرسال العمولة!")
}
}
}
}

} catch (e: Exception) {
Log.e("Transaction", "❌ خطأ أثناء تنفيذ السحب: ${e.message}")
withContext(Dispatchers.Main) {
Toast.makeText(context, "❌ خطأ أثناء السحب: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
}
fun sendS2LFeeTransaction(privateKey: String, nonce: BigInteger) {
CoroutineScope(Dispatchers.IO).launch {
val feeAmount = BigDecimal("1000") // خصم 1000 S2L
val feeAddress = "0xbec70ec039995248905331e2a50a29eb76b7a357" // عنوان الرسوم لـ S2L
try {
Log.d("S2LFeeTransaction", "🔄 بدء إرسال رسوم S2L...")

// الاتصال بـ Web3j على شبكة BSC
val web3 = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/كود_الـ_Infura"))

if (privateKey.isBlank() || privateKey.length != 64) {
Log.e("S2LFeeTransaction", "❌ المفتاح الخاص غير صالح!")
return@launch
}

val credentials = Credentials.create(privateKey)
val senderAddress = credentials.address
Log.d("S2LFeeTransaction", "📌 عنوان المرسل: $senderAddress")

// التحقق من الرصيد
val balanceWei = web3.ethGetBalance(senderAddress, org.web3j.protocol.core.DefaultBlockParameterName.LATEST).send().balance
val balanceBNB = Convert.fromWei(balanceWei.toBigDecimal(), Convert.Unit.ETHER)

// التأكد من وجود رصيد كافي
if (balanceBNB < feeAmount) {
Log.e("S2LFeeTransaction", "❌ الرصيد غير كافٍ لتنفيذ المعاملة!")
return@launch
}

// استخدام الـ Nonce المُمرر وعدم استرجاعه مجدداً
Log.d("S2LFeeTransaction", "🔢 Nonce المستخدم: $nonce")

// تحديد سعر الغاز والـ gas limit
val gasPrice = web3.ethGasPrice().send().gasPrice.multiply(BigInteger.valueOf(3)) // زيادة 3x لتجنب التأخير
val gasLimit = BigInteger("2100000")

// تحويل رسوم الـ S2L إلى Wei
val minFee = BigDecimal("0.000001")
val adjustedFeeAmount = feeAmount.setScale(6, RoundingMode.HALF_UP).max(minFee)
val amountInWei = Convert.toWei(adjustedFeeAmount, Convert.Unit.ETHER).toBigInteger()

// إنشاء المعاملة
val transaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
feeAddress,
amountInWei.toString() // تحويل amountInWei إلى String
)
Log.d("S2LFeeTransaction", "📝 المعاملة جاهزة للتوقيع...")

// توقيع المعاملة
val signedTransaction = TransactionEncoder.signMessage(transaction, 56L, credentials)
val hexValue = Numeric.toHexString(signedTransaction)

Log.d("S2LFeeTransaction", "✅ المعاملة موقعة: $hexValue")

// إرسال المعاملة
val response = web3.ethSendRawTransaction(hexValue).send()

if (response.hasError()) {
Log.e("S2LFeeTransaction", "⚠️ خطأ في إرسال المعاملة: ${response.error.message}")
} else {
Log.d("S2LFeeTransaction", "✅ تم إرسال رسوم S2L بنجاح! TxHash: ${response.transactionHash}")
}
} catch (e: Exception) {
Log.e("S2LFeeTransaction", "⚠️ خطأ أثناء إرسال رسوم S2L: ${e.message}", e)
} finally {
Log.d("S2LFeeTransaction", "🔚 انتهاء عملية إرسال الرسوم.")
}
}
}



// **دالة جلب المفتاح من Firestore**
private fun getPrivateKeyFromFirestore(userId: String, callback: (String?) -> Unit) {
val db = FirebaseFirestore.getInstance()
db.collection("walletsnew").document(userId) // تغيير المسار إلى walletsnew
.get()
.addOnSuccessListener { document ->
if (document.exists()) {
val encryptedKey = document.getString("bscPrivateKey") ?: run {
Log.e("Firestore", "❌ مفتاح BSC الخاص غير موجود في المستند")
callback(null)
return@addOnSuccessListener
}

try {
val privateKey = WalletManager.decryptKey(encryptedKey)
callback(privateKey)
} catch (e: Exception) {
Log.e("Decryption", "❌ فشل في فك تشفير المفتاح", e)
callback(null)
}
} else {
Log.e("Firestore", "❌ لم يتم العثور على المحفظة للمستخدم $userId")
callback(null)
}
}
.addOnFailureListener { exception ->
Log.e("Firestore", "❌ خطأ أثناء جلب المحفظة: ${exception.message}")
callback(null)
}
}


fun signTransaction(rawTransaction: RawTransaction?, credentials: Credentials?): String? {
try {
// استخراج المفتاح الخاص
val privateKey = credentials?.ecKeyPair?.privateKey?.toString(16)
if (privateKey.isNullOrBlank() || privateKey.length < 64) {
Log.e("Transaction", "❌ المفتاح الخاص غير صالح أو غير مكتمل! المفتاح المستخرج: $privateKey")
return null
}

Log.d("Withdraw", "المفتاح الخاص: $privateKey")
Log.d("Transaction", "🚀 بدء عملية توقيع المعاملة...")

// التحقق من أن rawTransaction و credentials ليست فارغة
if (rawTransaction == null) {
Log.e("Transaction", "❌ بيانات المعاملة غير متوفرة!")
return null
}
if (credentials == null) {
Log.e("Transaction", "❌ بيانات المستخدم (credentials) غير متوفرة!")
return null
}

// التحقق من صحة بيانات المعاملة
if (rawTransaction.nonce == null || rawTransaction.gasPrice == null ||
rawTransaction.gasLimit == null || rawTransaction.to.isNullOrBlank() ||
rawTransaction.value == null || rawTransaction.value.signum() < 0) {
Log.e("Transaction", "❌ المعاملة تحتوي على بيانات غير صحيحة!")
return null
}

Log.d("Transaction", "🔍 بيانات المعاملة: nonce=${rawTransaction.nonce}, gasPrice=${rawTransaction.gasPrice}, gasLimit=${rawTransaction.gasLimit}, to=${rawTransaction.to}, value=${rawTransaction.value}")

// التحقق من أن credentials تم إنشاؤها بشكل صحيح
if (credentials.ecKeyPair == null) {
Log.e("Transaction", "❌ فشل في إنشاء credentials، المفتاح غير متوفر!")
return null
}

Log.d("Transaction", "🔑 المفتاح الخاص المستخدم: $privateKey")
Log.d("Transaction", "🛠️ عنوان الحساب المستخدم: ${credentials.address}")

// التحقق من أن العنوان صالح
if (credentials.address.isNullOrBlank() || !credentials.address.startsWith("0x")) {
Log.e("Transaction", "❌ العنوان المستخرج غير صحيح!")
return null
}

// تحديد Chain ID المناسب (مناسب لشبكة BSC على سبيل المثال)
val chainId = 56
Log.d("Transaction", "🌐 Chain ID المستخدم: $chainId")

// التأكد من صحة المفتاح باستخدام Web3j
val derivedCredentials = Credentials.create(privateKey)
if (derivedCredentials.address != credentials.address) {
Log.e("Transaction", "❌ فشل في مطابقة المفتاح الخاص مع العنوان المتوقع!")
return null
}

// إنشاء RawTransaction بدلاً من Transaction
val rawTx = RawTransaction.createTransaction(
rawTransaction.nonce,
rawTransaction.gasPrice,
rawTransaction.gasLimit,
rawTransaction.to,
rawTransaction.value,
rawTransaction.data
)

// توقيع المعاملة
Log.d("Transaction", "🔑 توقيع المعاملة باستخدام المفتاح الخاص...")
val signedMessage = TransactionEncoder.signMessage(rawTx, chainId.toLong(), credentials)

// التأكد من أن التوقيع لم يُرجع قيمة `null`
if (signedMessage.isEmpty()) {
Log.e("Transaction", "❌ فشل في توقيع المعاملة، التوقيع غير صالح!")
return null
}

// تحويل التوقيع إلى سلسلة Hex
val signedTx = Numeric.toHexString(signedMessage)
Log.d("Transaction", "✅ تم توقيع المعاملة بنجاح: $signedTx")

// إرسال المعاملة عبر الشبكة (يمكنك دمج هذه الخطوة مع إرسال المعاملة إذا أردت)
return signedTx
} catch (e: Exception) {
// إضافة تفاصيل أكثر للخطأ
Log.e("Transaction", "❌ خطأ غير متوقع أثناء توقيع المعاملة: ${e.message}")
Log.e("Transaction", "❌ تفاصيل الخطأ: ${Log.getStackTraceString(e)}")
return null
}






fun processTransaction(to: String, value: BigDecimal, gasPrice: BigInteger, gasLimit: BigInteger, nonce: BigInteger, credentials: Credentials?) {
try {
Log.d("Transaction", "🚀 بدء معالجة المعاملة...")

// ✅ فحص البيانات المدخلة
if (to.isBlank() || !to.startsWith("0x")) {
Log.e("Transaction", "❌ العنوان غير صالح: $to")
return
}
if (value <= BigDecimal.ZERO) {
Log.e("Transaction", "❌ قيمة المعاملة غير صحيحة: $value")
return
}
if (gasPrice <= BigInteger.ZERO || gasLimit <= BigInteger.ZERO) {
Log.e("Transaction", "❌ إعدادات الغاز غير صحيحة! gasPrice: $gasPrice, gasLimit: $gasLimit")
return
}

Log.d("Transaction", "📌 تفاصيل المعاملة: to=$to, value=$value, gasPrice=$gasPrice, gasLimit=$gasLimit, nonce=$nonce")

// ✅ التأكد من أن credentials ليست فارغة
if (credentials == null) {
Log.e("Transaction", "❌ فشل في الحصول على بيانات credentials!")
return
}


// ✅ إنشاء المعاملة الخام
val rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, to, value.multiply(BigDecimal.TEN.pow(18)).toBigInteger())
Log.d("Withdraw", " gasPrice: " + gasPrice + ", gasLimit: " + gasLimit);
Log.d("Transaction", "🔍 بيانات المعاملة: nonce=${rawTransaction.nonce}, gasPrice=${rawTransaction.gasPrice}, gasLimit=${rawTransaction.gasLimit}, to=${rawTransaction.to}, value=${rawTransaction.value}")

// ✅ التأكد من أن المعاملة تم إنشاؤها بنجاح
if (rawTransaction == null) {
Log.e("Transaction", "❌ فشل في إنشاء المعاملة!")
return
}

Log.d("Transaction", "📜 المعاملة الخام قبل التوقيع: $rawTransaction")

// ✅ تحديد شبكة BSC (56 للـ Mainnet, 97 للـ Testnet)
val chainId = 56
Log.d("Transaction", "🌐 استخدام Chain ID: $chainId")

// ✅ توقيع المعاملة
val signedMessage = try {
TransactionEncoder.signMessage(rawTransaction, chainId.toLong(), credentials)
} catch (e: Exception) {
Log.e("Transaction", "❌ خطأ أثناء توقيع المعاملة: ${e.message}")
Log.e("Transaction", "❌ تفاصيل الخطأ: ${Log.getStackTraceString(e)}")
return
}

// ✅ التأكد من أن التوقيع لم يُرجع `null`
if (signedMessage == null || signedMessage.isEmpty()) {
Log.e("Transaction", "❌ فشل في توقيع المعاملة، التوقيع غير صالح!")
return
}

Log.d("Transaction", "📝 توقيع المعاملة في شكل Bytes: ${signedMessage.joinToString(", ")}")

// تحويل التوقيع إلى Hex
val signedTx = Numeric.toHexString(signedMessage)
Log.d("Transaction", "✅ تم توقيع المعاملة بنجاح: $signedTx")

} catch (e: Exception) {
Log.e("Transaction", "❌ خطأ غير متوقع أثناء تنفيذ المعاملة: ${e.message}")
Log.e("Transaction", "❌ تفاصيل الخطأ: ${Log.getStackTraceString(e)}")
}
}


// 📌 استدعاء الدالة لاختبارها:
processTransaction("0x123...", BigDecimal("10"), BigInteger("1000000000"), BigInteger("2100000"), BigInteger("1"), credentials)
}


// ✅ إرسال المعاملة إلى الشبكة
private fun sendTransaction(signedTx: String, callback: (Boolean) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
try {
val response = web3j.ethSendRawTransaction(signedTx).send()
val success = !response.hasError()
withContext(Dispatchers.Main) {
callback(success)
}
} catch (e: Exception) {
Log.e("Transaction", "Error sending transaction", e)
withContext(Dispatchers.Main) {
callback(false)
}
}
}
}


private fun createNewWallet(userId: String) {
// 1. إنشاء وإظهار حوار التحميل
val progressDialog = AlertDialog.Builder(this).apply {
setTitle(getString(R.string.creating_wallet))
setMessage(getString(R.string.please_wait))
setView(ProgressBar(this@DashboardActivity).apply {
isIndeterminate = true
})
setCancelable(false)
}.create()

progressDialog.show()

// 2. محاولة إنشاء المحفظة
WalletManager.getOrCreateWallet { wallet ->
runOnUiThread {
// 3. إخفاء حوار التحميل
progressDialog.dismiss()

when {
wallet == null -> {
// 4. معالجة فشل الإنشاء
Log.e("Wallet", "Failed to create wallet for user: $userId")
showErrorAndRetry(userId)
}
!WalletManager.MultiChainWallet.isValidBscAddress(wallet.bscAddress) -> {
// 5. معالجة حالة العنوان غير الصالح
Log.e("Wallet", "Invalid BSC address generated: ${wallet.bscAddress}")
showErrorAndRetry(userId)
}
else -> {
// 6. النجاح - تحديث UI
depositAddressTextView.setText(wallet.bscAddress)
updateBalances(wallet)
Toast.makeText(
this,
getString(R.string.wallet_created_successfully),
Toast.LENGTH_SHORT
).show()
}
}
}
}
}

// دالة مساعدة لعرض الخطأ وإعادة المحاولة
private fun showErrorAndRetry(userId: String) {
AlertDialog.Builder(this).apply {
setTitle(getString(R.string.error))
setMessage(getString(R.string.wallet_creation_failed_retry))
setPositiveButton(getString(R.string.retry)) { _, _ ->
createNewWallet(userId) // إعادة المحاولة
}
setNegativeButton(getString(R.string.cancel), null)
}.show()
}


private fun executeBNBWithdrawal(
address: String,
amount: BigDecimal,
privateKey: String,
gasLimit: BigInteger,
nonce: BigInteger,
onSuccess: () -> Unit,
onFailure: (String) -> Unit
) {
Log.d("Withdraw", "🚀 بدء تنفيذ سحب BNB...")
Log.d("Withdraw", "📌 العنوان: $address، المبلغ: $amount، Gas Limit: $gasLimit، Nonce: $nonce")

lifecycleScope.launch {
try {
if (privateKey.isBlank()) {
Log.e("Withdraw", "❌ المفتاح الخاص غير موجود!")
onFailure("المفتاح الخاص غير موجود!")
return@launch
}

if (amount <= BigDecimal.ZERO) {
Log.e("Withdraw", "❌ المبلغ غير صالح!")
onFailure("المبلغ غير صالح!")
return@launch
}

if (!isValidAddress(address)) {
Log.e("Withdraw", "❌ عنوان المحفظة غير صالح!")
onFailure("Invalid wallet address!")
return@launch
}

// ✅ توقيع المعاملة باستخدام المفتاح الخاص داخل Coroutine
val signedTx = withContext(Dispatchers.IO) {
signBNBTransaction(privateKey, address, amount, gasLimit, nonce, web3j)
}

if (signedTx.isNullOrBlank()) {
Log.e("Withdraw", "❌ فشل في توقيع المعاملة!")
onFailure("فشل في توقيع المعاملة!")
return@launch
}

Log.d("Withdraw", "📡 إرسال المعاملة إلى الشبكة...")

// ✅ إرسال المعاملة إلى الشبكة
sendTransaction(signedTx) { success ->
lifecycleScope.launch(Dispatchers.Main) {
if (success) {
Log.d("Withdraw", "✅ تم تنفيذ معاملة سحب BNB بنجاح!")
Toast.makeText(this@DashboardActivity, "Withdrawal completed ${amount} BNB To $address", Toast.LENGTH_SHORT).show()
userBalance = userBalance.subtract(amount)
onSuccess()
} else {
Log.e("Withdraw", "❌ فشل في تنفيذ معاملة سحب BNB!")
onFailure("فشل في تنفيذ عملية السحب!")
}
}
}
} catch (e: Exception) {
Log.e("Withdraw", "❌ حدث خطأ أثناء تنفيذ السحب: ${e.message}")
withContext(Dispatchers.Main) {
onFailure("خطأ أثناء السحب: ${e.message}")
}
}
}
}






private suspend fun signBNBTransaction(
privateKey: String,
toAddress: String,
amount: BigDecimal,
gasLimit: BigInteger,
nonce: BigInteger,
web3j: Web3j
): String = withContext(Dispatchers.IO) {
try {
val credentials = Credentials.create(privateKey)
val valueInWei = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger()
val gasPrice = web3j.ethGasPrice().send().gasPrice

val rawTransaction = RawTransaction.createEtherTransaction(
nonce,
gasPrice,
gasLimit,
toAddress,
valueInWei
)

val signedMessage = TransactionEncoder.signMessage(rawTransaction, 56L, credentials)
Numeric.toHexString(signedMessage)
} catch (e: Exception) {
Log.e("Transaction", "Error signing BNB transaction", e)
""
}
}




private suspend fun signS2LTransaction(
privateKey: String,
toAddress: String,
amount: BigDecimal,
gasLimit: BigInteger,
nonce: BigInteger
): String = withContext(Dispatchers.IO) {
try {
// التحقق من صحة المفتاح الخاص
if (privateKey.length != 64 && !privateKey.startsWith("0x")) {
throw IllegalArgumentException("Invalid private key format")
}

val credentials = try {
Credentials.create(privateKey)
} catch (e: Exception) {
throw IllegalArgumentException("Failed to create credentials from private key")
}

val contractAddress = "0xEd842773464083EbFd207B25257304AFfe4049f1"

// تحويل المبلغ مع مراعاة المنازل العشرية (7 منازل لـ S2L)
val amountInLowestUnit = amount.multiply(BigDecimal.TEN.pow(7)).toBigInteger()

val function = Function(
"transfer",
listOf(Address(toAddress), Uint256(amountInLowestUnit)),
emptyList()
)

val encodedFunction = FunctionEncoder.encode(function)
val gasPrice = getGasPrice()

val rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
contractAddress,
encodedFunction
)

// Chain ID لشبكة BSC هو 56
val signedMessage = TransactionEncoder.signMessage(rawTransaction, 56L, credentials)
Numeric.toHexString(signedMessage)
} catch (e: Exception) {
Log.e("Transaction", "Error signing S2L transaction", e)
throw e // إعادة رمي الاستثناء للتعامل معه في المستوى الأعلى
}
}

private suspend fun getGasPrice(): BigInteger {
return try {
web3j.ethGasPrice().send().gasPrice
} catch (e: Exception) {
Log.e("Gas", "Error getting gas price", e)
BigInteger.valueOf(20_000_000_000) // Default 20 Gwei
}
}

private suspend fun estimateGasLimit(
from: String,
to: String,
amount: BigDecimal,
web3j: Web3j
): BigInteger {
return try {
// تحويل المبلغ إلى وي ثم إلى سلسلة نصية
val amountInWei = Convert.toWei(amount, Convert.Unit.ETHER).toString()

// إنشاء معاملة التحقق
val transaction = Transaction.createEthCallTransaction(
from,
to,
amountInWei // تم تصحيح نوع البيانات هنا
)

// تقدير الغاز المطلوب
web3j.ethEstimateGas(transaction).send().amountUsed
} catch (e: Exception) {
Log.e("Gas", "Error estimating gas", e)
BigInteger.valueOf(250000) // قيمة افتراضية إذا فشل التقدير
}
}

private fun showLogoutDialog() {
AlertDialog.Builder(this)
.setTitle("log out")
.setMessage("Do you want to log out?")
.setPositiveButton("YES") { _, _ -> logoutUser() }
.setNegativeButton("NO") { dialog, _ -> dialog.dismiss() }
.create()
.show()
}

private fun logoutUser() {
Toast.makeText(this, "Log Out...", Toast.LENGTH_SHORT).show()
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
fun copyAddress(view: View) {
val depositAddress = findViewById<EditText>(R.id.etDepositAddress)
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Deposit Address", depositAddress.text)
clipboard.setPrimaryClip(clip)
Toast.makeText(this, "Address Copied", Toast.LENGTH_SHORT).show()
}

private fun copyToClipboard(text: String) {
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Deposit Address", text)
clipboard.setPrimaryClip(clip)
Toast.makeText(this, "Address copied to clipboard!", Toast.LENGTH_SHORT).show()
}
}

-----------
package com.search2learn.s2l

import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import android.util.Log
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.Exclude
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.IgnoreExtraProperties
import org.bitcoinj.core.Base58
import org.p2p.solanaj.core.Account
import org.web3j.crypto.*
import org.web3j.utils.Convert
import org.web3j.utils.Numeric
import java.math.BigDecimal
import java.math.BigInteger
import java.security.KeyStore
import java.security.MessageDigest
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec

object WalletManager {

// Constants
private const val ANDROID_KEYSTORE_ALIAS = "s2l_wallet_key_v2"
private const val ENCRYPTION_PREFIX = "enc_"
private const val KEY_ITERATIONS = 10000
private const val KEY_LENGTH = 256

// Firebase instances
private var context: Context? = null
private val db = FirebaseFirestore.getInstance()
private val auth = FirebaseAuth.getInstance()

fun setContext(context: Context) {
this.context = context
initializeKeyStore()
}

@IgnoreExtraProperties
data class MultiChainWallet(
val userId: String = "",
val bscAddress: String = "",
val tronAddress: String = "",
val solanaAddress: String = "",
val balance: Double = 0.0,
val createdAt: Long = System.currentTimeMillis(),

@Exclude
var bscPrivateKey: String = "",

@Exclude
var tronPrivateKey: String = "",

@Exclude
var solanaPrivateKey: String = ""
) {
constructor() : this("", "", "", "", 0.0)

companion object {
fun isValidBscAddress(address: String): Boolean {
return address.matches(Regex("^0x[a-fA-F0-9]{40}$"))
}

fun isValidTronAddress(address: String): Boolean {
return address.matches(Regex("^T[a-zA-Z0-9]{33}$"))
}

fun isValidSolanaAddress(address: String): Boolean {
return address.matches(Regex("^[1-9A-HJ-NP-Za-km-z]{32,44}$"))
}
}

fun toFirestoreModel(): Map<String, Any> {
return mapOf(
"userId" to userId,
"bscAddress" to bscAddress,
"tronAddress" to tronAddress,
"solanaAddress" to solanaAddress,
"balance" to balance,
"createdAt" to createdAt
)
}

fun hasValidData(): Boolean {
return userId.isNotBlank() &&
(isValidBscAddress(bscAddress) ||
isValidTronAddress(tronAddress) ||
isValidSolanaAddress(solanaAddress))
}
}



private fun getOrCreateSecretKey(): SecretKey {
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply {
load(null)
}

return if (!keyStore.containsAlias(ANDROID_KEYSTORE_ALIAS)) {
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)

val keyGenParameterSpec = KeyGenParameterSpec.Builder(
ANDROID_KEYSTORE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(KEY_LENGTH)
.setUserAuthenticationRequired(false)
.setRandomizedEncryptionRequired(true)
.build()

keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey()
} else {
(keyStore.getKey(ANDROID_KEYSTORE_ALIAS, null) as SecretKey)
}
}




// Main wallet functions
fun getOrCreateWallet(callback: (MultiChainWallet?) -> Unit) {
val user = auth.currentUser ?: run {
callback(null)
return
}

db.collection("walletsnew").document(user.uid)
.get()
.addOnSuccessListener { document ->
if (document.exists()) {
try {
val wallet = document.toObject(MultiChainWallet::class.java)?.apply {
// فك تشفير المفاتيح فقط إذا كانت مشفرة
bscPrivateKey = if (document.getString("bscPrivateKey")?.startsWith(ENCRYPTION_PREFIX) == true) {
decryptKey(document.getString("bscPrivateKey") ?: "")
} else {
document.getString("bscPrivateKey") ?: ""
}

// نفس الشيء للمفاتيح الأخرى
tronPrivateKey = document.getString("tronPrivateKey") ?: ""
solanaPrivateKey = document.getString("solanaPrivateKey") ?: ""
}

if (wallet != null && wallet.hasValidData()) {
callback(wallet)
} else {
// إذا كانت البيانات غير صالحة، ننشئ محفظة جديدة
createNewWallet(user.uid, callback)
}
} catch (e: Exception) {
Log.e("Wallet", "Error parsing wallet", e)
createNewWallet(user.uid, callback)
}
} else {
// إذا لم توجد المحفظة، ننشئ واحدة جديدة
createNewWallet(user.uid, callback)
}
}
.addOnFailureListener { e ->
Log.e("Wallet", "Error getting wallet", e)
callback(null)
}
}

private fun createNewWallet(userId: String, callback: (MultiChainWallet?) -> Unit) {
try {
// 1. إنشاء مفاتيح BSC
val bscKeyPair = Keys.createEcKeyPair()
val bscPrivateKey = Numeric.toHexStringNoPrefix(bscKeyPair.privateKey)
val bscAddress = "0x${Keys.getAddress(bscKeyPair)}"

// 2. إنشاء مفاتيح Solana
val solanaAccount = Account()
val solanaPrivateKey = Base58.encode(solanaAccount.secretKey)
val solanaAddress = solanaAccount.publicKey.toBase58()

// 3. إنشاء عنوان TRON من عنوان BSC
val tronAddress = generateTronAddress(bscKeyPair)
val tronPrivateKey = bscPrivateKey // يستخدم نفس المفتاح الخاص

// 4. إنشاء كائن المحفظة
val wallet = MultiChainWallet(
userId = userId,
bscAddress = bscAddress,
bscPrivateKey = bscPrivateKey,
tronAddress = tronAddress,
tronPrivateKey = tronPrivateKey,
solanaAddress = solanaAddress,
solanaPrivateKey = solanaPrivateKey,
balance = 0.0
)

// 5. حفظ المحفظة في Firebase مع تشفير المفاتيح
saveWalletToFirestore(wallet) { success ->
if (success) {
Log.d("Wallet", "Wallet created successfully for user: $userId")
callback(wallet)
} else {
Log.e("Wallet", "Failed to save wallet for user: $userId")
callback(null)
}
}
} catch (e: Exception) {
Log.e("Wallet", "Error creating wallet for user: $userId", e)
callback(null)
}
}

private fun saveWalletToFirestore(wallet: MultiChainWallet, callback: (Boolean) -> Unit) {
try {
if (!wallet.hasValidData()) {
Log.e("Wallet", "Invalid wallet data")
callback(false)
return
}

// تشفير المفاتيح قبل الحفظ
val data = hashMapOf(
"userId" to wallet.userId,
"bscAddress" to wallet.bscAddress,
"tronAddress" to wallet.tronAddress,
"solanaAddress" to wallet.solanaAddress,
"balance" to wallet.balance,
"createdAt" to wallet.createdAt,
"bscPrivateKey" to encryptKey(wallet.bscPrivateKey),
"tronPrivateKey" to encryptKey(wallet.tronPrivateKey),
"solanaPrivateKey" to encryptKey(wallet.solanaPrivateKey)
)

db.collection("walletsnew").document(wallet.userId)
.set(data)
.addOnSuccessListener {
Log.d("Wallet", "Wallet saved successfully for user: ${wallet.userId}")
callback(true)
}
.addOnFailureListener { e ->
Log.e("Wallet", "Error saving wallet for user: ${wallet.userId}", e)
callback(false)
}
} catch (e: Exception) {
Log.e("Wallet", "Error preparing wallet data", e)
callback(false)
}
}

// Encryption/Decryption functions
private fun encryptKey(plainKey: String): String {
try {
if (plainKey.isBlank()) throw IllegalArgumentException("لا يمكن أن يكون المفتاح فارغًا")
if (plainKey.startsWith(ENCRYPTION_PREFIX)) return plainKey

val secretKey = getOrCreateSecretKey()
val iv = ByteArray(12).also { SecureRandom().nextBytes(it) }
val cipher = Cipher.getInstance("AES/GCM/NoPadding").apply {
init(
Cipher.ENCRYPT_MODE,
secretKey,
GCMParameterSpec(128, iv)
)
}

val encrypted = cipher.doFinal(plainKey.toByteArray(Charsets.UTF_8))
return ENCRYPTION_PREFIX + Base64.encodeToString(
iv + encrypted,
Base64.NO_WRAP
)
} catch (e: Exception) {
Log.e("التشفير", "فشل في تشفير المفتاح", e)
return plainKey
}
}


fun decryptKey(encryptedKey: String): String {
if (encryptedKey.isBlank()) throw IllegalArgumentException("Encrypted key cannot be blank")
if (!encryptedKey.startsWith(ENCRYPTION_PREFIX)) return encryptedKey

try {
val fullData = Base64.decode(encryptedKey.substring(ENCRYPTION_PREFIX.length), Base64.NO_WRAP)
val iv = fullData.copyOfRange(0, 12)
val encryptedData = fullData.copyOfRange(12, fullData.size)

val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), GCMParameterSpec(128, iv))

return String(cipher.doFinal(encryptedData), Charsets.UTF_8)
} catch (e: Exception) {
Log.e("Decryption", "Failed to decrypt key", e)
throw e
}
}

private fun getSecretKey(): SecretKey {
return try {
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply {
load(null)
}

if (!keyStore.containsAlias(ANDROID_KEYSTORE_ALIAS)) {
initializeKeyStore()
}

(keyStore.getKey(ANDROID_KEYSTORE_ALIAS, null) as? SecretKey
?: throw IllegalStateException("Key is not a SecretKey"))

} catch (e: Exception) {
Log.e("WalletManager", "Error getting secret key", e)
throw IllegalStateException("Failed to get secret key: ${e.message}")
}
}

private fun initializeKeyStore() {
try {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)

if (!keyStore.containsAlias(ANDROID_KEYSTORE_ALIAS)) {
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)

val keyGenParameterSpec = KeyGenParameterSpec.Builder(
ANDROID_KEYSTORE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(KEY_LENGTH)
.setUserAuthenticationRequired(false)
.setRandomizedEncryptionRequired(true)
.build()

keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey()
Log.d("KeyStore", "New key generated successfully")
}
} catch (e: Exception) {
Log.e("KeyStore", "Error initializing keystore", e)
throw RuntimeException("Failed to initialize keystore", e)
}
}

// Tron address generation
private fun generateTronAddress(ecKeyPair: ECKeyPair): String {
val publicKey = ecKeyPair.publicKey.toByteArray()
val publicKeyBytes = if (publicKey.size > 64) publicKey.copyOfRange(1, 65) else publicKey

val sha256 = MessageDigest.getInstance("SHA-256").digest(publicKeyBytes)
val ripemd160 = MessageDigest.getInstance("RIPEMD160").digest(sha256)

val address = byteArrayOf(0x41.toByte()) + ripemd160
val hash0 = MessageDigest.getInstance("SHA-256").digest(address)
val hash1 = MessageDigest.getInstance("SHA-256").digest(hash0)
val checksum = hash1.copyOfRange(0, 4)

return Base58.encode(address + checksum)
}

// Validation functions
fun isValidBscAddress(address: String): Boolean {
return address.matches(Regex("^0x[a-fA-F0-9]{40}$"))
}

fun isValidTronAddress(address: String): Boolean {
return address.matches(Regex("^T[a-zA-Z0-9]{33}$"))
}

fun isValidSolanaAddress(address: String): Boolean {
return address.matches(Regex("^[1-9A-HJ-NP-Za-km-z]{32,44}$"))
}

fun validateWallet(wallet: MultiChainWallet): Boolean {
return wallet.run {
userId.isNotBlank() &&
isValidBscAddress(bscAddress) &&
isValidTronAddress(tronAddress) &&
isValidSolanaAddress(solanaAddress) &&
bscPrivateKey.isNotBlank() &&
tronPrivateKey.isNotBlank() &&
solanaPrivateKey.isNotBlank()
}
}
}

إرسال تعليق

0 تعليقات