Ticker

6/recent/ticker-posts

Header Ads Widget

JustMarkets

 




package com.search2learn.s2l

import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.math.RoundingMode
import org.web3j.abi.FunctionReturnDecoder
import org.web3j.protocol.core.methods.response.TransactionReceipt
import android.content.Context
import android.widget.Toast
import kotlinx.coroutines.*
import org.web3j.crypto.Credentials
import org.web3j.crypto.RawTransaction
import org.web3j.crypto.TransactionEncoder
import org.web3j.protocol.Web3j
import org.web3j.protocol.core.DefaultBlockParameterName
import org.web3j.protocol.http.HttpService
import org.web3j.utils.Convert
import org.web3j.utils.Numeric
import android.util.Log
import java.math.BigDecimal
import java.math.BigInteger
import org.web3j.abi.datatypes.generated.Uint256
import org.web3j.protocol.core.methods.request.Transaction
import org.web3j.abi.datatypes.Function
import org.web3j.abi.datatypes.Address
import org.web3j.abi.TypeReference
import org.web3j.abi.FunctionEncoder
import org.web3j.protocol.core.methods.response.Log as Web3Log
import org.web3j.protocol.core.methods.request.EthFilter
import org.web3j.crypto.Keys
import android.app.ProgressDialog
import org.web3j.protocol.core.methods.response.EthSendTransaction
import org.web3j.protocol.core.methods.response.EthEstimateGas
import org.web3j.protocol.core.methods.response.EthGasPrice
import org.web3j.protocol.core.methods.response.EthGetTransactionCount

object Web3Utils {



// عنوان Infura أو مزود الشبكة، تأكد من صحته
private const val INFURA_URL = "https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"
private val web3j: Web3j = Web3j.build(HttpService(INFURA_URL))


private const val TOKEN_CONTRACT_ADDRESS = "0xEd842773464083EbFd207B25257304AFfe4049f1"
// تعريف TAG لتسهيل تتبع الرسائل في السجل
private const val TAG = "Web3Utils"





// دالة لجلب النونس بناءً على العنوان المرسل
fun getNonce(address: String): BigInteger? {
return try {
val nonce = web3j.ethGetTransactionCount(
address, DefaultBlockParameterName.LATEST
).send().transactionCount
nonce
} catch (e: Exception) {
Log.e("Web3Utils", "Error fetching nonce for address: $address", e)
null
}
}



@OptIn(kotlin.ExperimentalStdlibApi::class)
fun withdrawBNB(context: Context, toAddress: String, amount: BigDecimal, privateKey: String) {
CoroutineScope(Dispatchers.IO).launch {
val result = try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

Log.d(TAG, "From Address: $fromAddress")
Log.d(TAG, "To Address: $toAddress")
Log.d(TAG, "Requested Amount: $amount BNB")

// ✅ التحقق من الرصيد
val balance = getBalance(fromAddress)
val balanceBD = Convert.fromWei(BigDecimal(balance.toString()), Convert.Unit.ETHER)

if (balanceBD < amount) {
Log.e(TAG, " Insufficient balance!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Insufficient balance!", Toast.LENGTH_SHORT).show()
}
return@launch
}


// ✅ جلب nonce
val nonce = try {
web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send().transactionCount
} catch (e: Exception) {
Log.e(TAG, " Error getting nonce: ${e.message}")
return@launch
}
Log.d(TAG, "Nonce: $nonce")

// ✅ جلب سعر الغاز وتحديد الحد
val gasPrice = try {
web3j.ethGasPrice().send().gasPrice
} catch (e: Exception) {
Log.e(TAG, " Error getting gas price: ${e.message}")
return@launch
}

val gasLimit = BigInteger.valueOf(21000)
val gasFee = gasPrice.multiply(gasLimit)
val gasFeeBNB = Convert.fromWei(gasFee.toBigDecimal(), Convert.Unit.ETHER)

Log.d(TAG, "Gas Price: $gasPrice, Gas Limit: $gasLimit, Estimated Fee: $gasFeeBNB BNB")

// ✅ التحقق من أن الرصيد يغطي المبلغ والرسوم
val totalRequired = amount.add(gasFeeBNB)
if (balanceBD < totalRequired) {
Log.e(TAG, " Not enough balance to cover transaction + gas fee!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Insufficient balance for gas fees!", Toast.LENGTH_SHORT).show()
}
return@launch
}

// ✅ تحويل المبلغ إلى wei
val weiAmount = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger()
val rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, toAddress, weiAmount)

// ✅ توقيع المعاملة
val signedMessage = try {
TransactionEncoder.signMessage(rawTransaction, credentials)
} catch (e: Exception) {
Log.e(TAG, " Error signing transaction: ${e.message}")
return@launch
}

val hexValue = Numeric.toHexString(signedMessage)
Log.d(TAG, "Signed Transaction: $hexValue")

// ✅ إرسال المعاملة
val sendTransaction = web3j.ethSendRawTransaction(hexValue).send()
if (sendTransaction.hasError()) {
Log.e(TAG, " Transaction Error: ${sendTransaction.error.message}")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${sendTransaction.error.message}", Toast.LENGTH_SHORT).show()
}
return@launch
}

val transactionHash = sendTransaction.transactionHash
Log.d(TAG, " Transaction Hash: $transactionHash")

withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Sent: $transactionHash", Toast.LENGTH_LONG).show()
}

true
} catch (e: Exception) {
Log.e(TAG, " Exception: ${e.localizedMessage}", e)
false
}

withContext(Dispatchers.Main) {
val message = if (result) " Transaction sent successfully!" else " Transaction failed!"
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
}



private val web3: Web3j by lazy {
Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec")) // تأكد من وضع رابط الـ RPC الصحيح
}



fun getGasPrice(web3j: Web3j): BigInteger {
val ethGasPrice = web3j.ethGasPrice().send()
return ethGasPrice.gasPrice
}

suspend fun getNonce(address: String, web3j: Web3j): BigInteger {
return withContext(Dispatchers.IO) {
try {
val ethGetTransactionCount = web3j.ethGetTransactionCount(
address, DefaultBlockParameterName.PENDING
).send()
ethGetTransactionCount.transactionCount
} catch (e: Exception) {
e.printStackTrace()
BigInteger.ZERO // في حالة الفشل، يرجع 0 لتجنب الأخطاء
}
}
}




suspend fun getGasPrice(): BigInteger {
return withContext(Dispatchers.IO) { // 💡 نقل العملية إلى خيط منفصل
try {
val web3 = Web3Utils.getWeb3j()
val ethGasPrice: EthGasPrice = web3.ethGasPrice().send()
Log.d("Web3Utils", "✅ سعر الغاز الحالي: ${ethGasPrice.gasPrice}")
ethGasPrice.gasPrice
} catch (e: Exception) {
Log.e("Web3Utils", "⚠️ خطأ في جلب سعر الغاز: ${e.message}")
BigInteger.ZERO // 🛑 إرجاع 0 في حالة الفشل لتجنب كسر التطبيق
}
}
}

fun getWeb3j(): Web3j {
return Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec")) // تأكد من وضع رابط الـ RPC الصحيح
}


suspend fun getTokenBalance(
contractAddress: String,
walletAddress: String,
decimals: Int,
web3j: Web3j = getWeb3j() // قيمة افتراضية للتوافق مع الشيفرة القديمة
): BigDecimal {
return withContext(Dispatchers.IO) {
try {
val function = Function(
"balanceOf",
listOf(Address(walletAddress)),
listOf(object : TypeReference<Uint256>() {})
)
val encodedFunction = FunctionEncoder.encode(function)

val response = web3j.ethCall(
Transaction.createEthCallTransaction(null, contractAddress, encodedFunction),
DefaultBlockParameterName.LATEST
).send()

if (response.hasError()) {
Log.e("TokenBalance", "Error: ${response.error.message}")
return@withContext BigDecimal.ZERO
}

val balance = BigInteger(response.value.substring(2), 16)
BigDecimal(balance).movePointLeft(decimals)
} catch (e: Exception) {
Log.e("TokenBalance", "Error: ${e.message}")
BigDecimal.ZERO
}
}
}


fun getTokenBalanceForToken(contractAddress: String, walletAddress: String, decimals: Int): BigDecimal {
Log.d(TAG, "🔎 جلب رصيد للرمز: $contractAddress, العنوان: $walletAddress, الأرقام العشرية: $decimals")

// التحقق من صحة عنوان المحفظة
if (walletAddress.isEmpty() || !walletAddress.startsWith("0x") || walletAddress.length != 42) {
Log.e(TAG, "❌ عنوان المحفظة غير صالح: $walletAddress")
return BigDecimal.ZERO
}

// التحقق من صحة عنوان العقد الذكي
if (contractAddress.isEmpty() || !contractAddress.startsWith("0x") || contractAddress.length != 42) {
Log.e(TAG, "❌ عنوان العقد الذكي غير صالح: $contractAddress")
return BigDecimal.ZERO
}

// التحقق من صحة عدد الأرقام العشرية
if (decimals < 0 || decimals > 18) {
Log.e(TAG, "❌ عدد الأرقام العشرية غير صالح: $decimals")
return BigDecimal.ZERO
}

return try {
val web3 = Web3j.build(HttpService("https://bsc-mainnet.infura.io/v3/c88ab0a11eb040438cff2f7bef79feec"))

// إنشاء دالة `balanceOf`
val function = Function(
"balanceOf",
listOf(Address(walletAddress)),
listOf(TypeReference.create(Uint256::class.java))
)

// ترميز الدالة
val encodedFunction = FunctionEncoder.encode(function)
Log.d(TAG, "📜 الدالة المرمزة: $encodedFunction")

// إرسال الطلب إلى العقد الذكي
val response = web3.ethCall(
Transaction.createEthCallTransaction(null, contractAddress, encodedFunction),
DefaultBlockParameterName.LATEST
).send()

Log.d(TAG, "🔍 الرد من العقد: ${response.value}")

// التحقق من أن الرد غير فارغ
if (response.value.isNullOrEmpty() || !response.value.startsWith("0x")) {
Log.e(TAG, "⚠️ لم يتم استرجاع أي رصيد أو القيمة غير صالحة!")
return BigDecimal.ZERO
}

// فك تشفير القيمة المُرجعة
val decoded = FunctionReturnDecoder.decode(response.value, function.outputParameters)
if (decoded.isEmpty()) {
Log.e(TAG, "⚠️ فشل فك تشفير القيمة المُرجعة!")
return BigDecimal.ZERO
}

// الحصول على الرصيد كـ BigInteger
val balance = (decoded[0] as Uint256).value
Log.d(TAG, "💰 الرصيد الخام: $balance")

// تحويل الرصيد إلى الوحدة الصحيحة باستخدام `decimals`
val formattedBalance = when (decimals) {
7 -> BigDecimal(balance).movePointLeft(7) // تحويل لـ S2L و S2LE
18 -> BigDecimal(balance).movePointLeft(18) // تحويل لـ USDT و BNB
else -> BigDecimal(balance).movePointLeft(decimals) // تحويل عام
}

Log.d(TAG, "✅ الرصيد الفعلي: $formattedBalance")
formattedBalance
} catch (e: Exception) {
Log.e(TAG, "❌ خطأ أثناء جلب الرصيد: ${e.message}", e)
BigDecimal.ZERO
}
}
fun withdrawToken(context: Context, web3j: Web3j, toAddress: String, amount: BigDecimal, privateKey: String, contractAddress: String, decimals: Int) {
val TAG = "Token_Withdraw"

// التحقق من صحة المفتاح الخاص
if (!isValidPrivateKey(privateKey)) {
Toast.makeText(context, " Invalid private key!", Toast.LENGTH_SHORT).show()
return
}

// تحقق من صحة عنوان الاستلام
if (!isValidAddress(toAddress)) {
Toast.makeText(context, " Invalid recipient address!", Toast.LENGTH_SHORT).show()
return
}

CoroutineScope(Dispatchers.IO).launch {
var result: String? = null
val progressDialog = ProgressDialog(context).apply {
setTitle("🔄 Processing")
setMessage("Please wait...")
setCancelable(false)
show()
}

try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

Log.d(TAG, "📌 From Address: $fromAddress")
Log.d(TAG, "📌 To Address: $toAddress")
Log.d(TAG, "📌 Requested Amount: $amount")

// ✅ التحقق من الرصيد
val balance = getTokenBalanceForToken(contractAddress, fromAddress, decimals)
Log.d(TAG, "💰 Token Balance: $balance")

if (balance < amount) {
Log.e(TAG, " Insufficient token balance!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Insufficient token balance!", Toast.LENGTH_SHORT).show()
}
return@launch
}

// ✅ حساب nonce
val nonce = web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send().transactionCount
Log.d(TAG, "🔢 Nonce: $nonce")

// ✅ جلب gasPrice
val gasPrice = web3j.ethGasPrice().send().gasPrice
Log.d(TAG, " Gas Price: $gasPrice")

// ✅ تحويل المبلغ إلى Wei
val tokenAmount = amount.movePointRight(decimals).toBigInteger()
Log.d(TAG, "📌 Token Amount in Wei: $tokenAmount")

// ✅ إعداد دالة التحويل
val function = Function(
"transfer",
listOf(Address(toAddress), Uint256(tokenAmount)),
emptyList()
)
val encodedFunction = FunctionEncoder.encode(function)
Log.d(TAG, "📜 Encoded Function: $encodedFunction")

// ✅ حساب الغاز التقديري
val estimatedGas = web3j.ethEstimateGas(
Transaction.createEthCallTransaction(fromAddress, contractAddress, encodedFunction)
).send().amountUsed
val gasLimit = estimatedGas.multiply(BigInteger.valueOf(2)) // زيادة الحد لتجنب الأخطاء
Log.d(TAG, " Estimated Gas: $estimatedGas, Gas Limit: $gasLimit")

// ✅ إنشاء المعاملة
val rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
contractAddress,
BigInteger.ZERO,
encodedFunction
)
Log.d(TAG, "📜 Raw Transaction Created")

// ✅ توقيع المعاملة
val signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials)
val hexValue = Numeric.toHexString(signedMessage)
Log.d(TAG, "✍️ Signed Transaction: $hexValue")

// ✅ إرسال المعاملة
val sendTransaction = web3j.ethSendRawTransaction(hexValue).send()
if (sendTransaction.hasError()) {
Log.e(TAG, " Transaction Error: ${sendTransaction.error.message}")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${sendTransaction.error.message}", Toast.LENGTH_SHORT).show()
}
return@launch
}

result = sendTransaction.transactionHash
Log.d(TAG, " Transaction Hash: $result")

withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Sent: $result", Toast.LENGTH_LONG).show()
}

} catch (e: Exception) {
Log.e(TAG, " Exception: ${e.localizedMessage}", e)
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
} finally {
progressDialog.dismiss()
}
}
}
@OptIn(kotlin.ExperimentalStdlibApi::class)
fun withdrawS2L(context: Context, web3j: Web3j, toAddress: String, amount: BigDecimal, privateKey: String) {
val TAG = "S2L_Withdraw"

// التحقق من صحة المفتاح الخاص
if (!isValidPrivateKey(privateKey)) {
Toast.makeText(context, " Invalid private key!", Toast.LENGTH_SHORT).show()
return
}

// تحقق من صحة عنوان الاستلام
if (!isValidAddress(toAddress)) {
Toast.makeText(context, " Invalid recipient address!", Toast.LENGTH_SHORT).show()
return
}

CoroutineScope(Dispatchers.IO).launch {
var result: String? = null
val progressDialog = ProgressDialog(context).apply {
setTitle("🔄 Processing")
setMessage("Please wait...")
setCancelable(false)
show()
}

try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

Log.d(TAG, "📌 From Address: $fromAddress")
Log.d(TAG, "📌 To Address: $toAddress")
Log.d(TAG, "📌 Requested Amount: $amount S2L")

// ✅ التحقق من الرصيد
val balance = Web3Utils.getTokenBalance(
contractAddress = "0xEd842773464083EbFd207B25257304AFfe4049f1", // عنوان العقد
walletAddress = "0xYourWalletAddressHere", // عنوان المحفظة
decimals = 7 // المنازل العشرية
)
Log.d(TAG, "💰 S2L Balance: $balance")

if (balance < amount) {
Log.e(TAG, " Insufficient S2L balance!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Insufficient S2L balance!", Toast.LENGTH_SHORT).show()
}
return@launch
}

// ✅ حساب nonce
val nonce = web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send().transactionCount
Log.d(TAG, "🔢 Nonce: $nonce")

// ✅ جلب gasPrice
val gasPrice = web3j.ethGasPrice().send().gasPrice
Log.d(TAG, " Gas Price: $gasPrice")

// ✅ تحويل المبلغ إلى Wei (مع مراعاة 7 منازل عشرية)
val tokenAmount = amount.movePointRight(7).toBigInteger()
Log.d(TAG, "📌 Token Amount in Wei: $tokenAmount")

// ✅ إعداد دالة التحويل
val function = Function(
"transfer",
listOf(Address(toAddress), Uint256(tokenAmount)),
emptyList()
)
val encodedFunction = FunctionEncoder.encode(function)
Log.d(TAG, "📜 Encoded Function: $encodedFunction")

// ✅ حساب الغاز التقديري
val estimatedGas = web3j.ethEstimateGas(
Transaction.createEthCallTransaction(fromAddress, TOKEN_CONTRACT_ADDRESS, encodedFunction)
).send().amountUsed
val gasLimit = estimatedGas.multiply(BigInteger.valueOf(2)) // زيادة الحد لتجنب الأخطاء
Log.d(TAG, " Estimated Gas: $estimatedGas, Gas Limit: $gasLimit")

// ✅ إنشاء المعاملة
val rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
TOKEN_CONTRACT_ADDRESS,
BigInteger.ZERO,
encodedFunction
)
Log.d(TAG, "📜 Raw Transaction Created")

// ✅ توقيع المعاملة
val signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials)
val hexValue = Numeric.toHexString(signedMessage)
Log.d(TAG, "✍️ Signed Transaction: $hexValue")

// ✅ إرسال المعاملة
val sendTransaction = web3j.ethSendRawTransaction(hexValue).send()
if (sendTransaction.hasError()) {
Log.e(TAG, " Transaction Error: ${sendTransaction.error.message}")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${sendTransaction.error.message}", Toast.LENGTH_SHORT).show()
}
return@launch
}

result = sendTransaction.transactionHash
Log.d(TAG, " Transaction Hash: $result")

withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Sent: $result", Toast.LENGTH_LONG).show()
}

} catch (e: Exception) {
Log.e(TAG, " Exception: ${e.localizedMessage}", e)
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
} finally {
progressDialog.dismiss()
}
}
}

// دالة سحب عملة S2L من المحفظة إلى عنوان آخر
fun withdrawS2L(web3j: Web3j, context: Context, toAddress: String, amount: BigDecimal, privateKey: String) {
val TAG = "S2L_Withdraw"

// التحقق من صحة المفتاح الخاص
if (!isValidPrivateKey(privateKey)) {
Toast.makeText(context, " Invalid private key!", Toast.LENGTH_SHORT).show()
return
}

// تحقق من صحة عنوان الاستلام
if (!isValidAddress(toAddress)) {
Toast.makeText(context, " Invalid recipient address!", Toast.LENGTH_SHORT).show()
return
}

// تشغيل العملية في خيط مستقل
CoroutineScope(Dispatchers.IO).launch {
var result: String? = null

val progressDialog = ProgressDialog(context).apply {
setTitle("🔄 Processing")
setMessage("Please wait...")
setCancelable(false)
show()
}

try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

Log.d(TAG, "📌 From Address: $fromAddress")
Log.d(TAG, "📌 To Address: $toAddress")
Log.d(TAG, "📌 Requested Amount: $amount S2L")

// حساب nonce
val nonce = fetchNonce(web3j, fromAddress)
Log.d(TAG, "🔢 Nonce: $nonce")

// التحقق من صحة nonce
if (nonce < BigInteger.ZERO) {
Log.e(TAG, " Invalid nonce: $nonce")
withContext(Dispatchers.Main) {
Toast.makeText(context, " Failed to fetch nonce!", Toast.LENGTH_SHORT).show()
}
return@launch
}

// الحصول على gasPrice
val gasPrice = fetchGasPrice(web3j)
Log.d(TAG, " Gas Price: $gasPrice wei")

// التحقق من صحة gasPrice
if (gasPrice <= BigInteger.ZERO) {
Log.e(TAG, " Invalid gas price: $gasPrice")
withContext(Dispatchers.Main) {
Toast.makeText(context, " Failed to fetch gas price!", Toast.LENGTH_SHORT).show()
}
return@launch
}

// تحويل المبلغ إلى Wei
Log.d(TAG, "📌 Amount before conversion: $amount")

val tokenAmount = amount.movePointRight(7).toBigInteger()
Log.d(TAG, "📌 Token Amount after conversion: $tokenAmount")

Log.d(TAG, "💰 Token Amount in Wei: $tokenAmount")

// إعداد دالة transfer
val encodedFunction = encodeTransferFunction(toAddress, tokenAmount)
Log.d(TAG, "📜 Encoded Transfer Function: $encodedFunction")

// حساب الغاز التقديري
val estimatedGas = estimateGas(web3j, fromAddress, encodedFunction)
Log.d(TAG, " Estimated Gas: $estimatedGas")

// ضبط حد الغاز
val gasLimit = if (estimatedGas > BigInteger.ZERO) {
estimatedGas.multiply(BigInteger.valueOf(2)) // مضاعفة حسب الحاجة
} else {
BigInteger.valueOf(1200000) // قيمة احتياطية
}
Log.d(TAG, "🚀 Final Gas Limit: $gasLimit")

// إنشاء معاملة العقد الذكي
val rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, TOKEN_CONTRACT_ADDRESS, BigInteger.ZERO, encodedFunction)
Log.d(TAG, "📜 Created Raw Transaction")

// توقيع المعاملة
val signedTransaction = TransactionEncoder.signMessage(rawTransaction, credentials)
val hexValue = Numeric.toHexString(signedTransaction)
Log.d(TAG, "✍️ Signed Transaction: $hexValue")

// إرسال المعاملة إلى الشبكة
result = sendTransaction(web3j, hexValue)
Log.d(TAG, "📡 Transaction Sent: $result")

} catch (e: Exception) {
Log.e(TAG, " Error sending S2L transaction: ${e.message}", e)
} finally {
progressDialog.dismiss()
}

// عرض نتيجة العملية
withContext(Dispatchers.Main) {
val message = if (result != null) {
" Transaction sent successfully! Hash: $result"
} else {
" Transaction failed! Check the logs for details."
}
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
}






// الوظائف المساعدة
private fun fetchNonce(web3j: Web3j, fromAddress: String): BigInteger {
val transactionCountResponse: EthGetTransactionCount = web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send()
return transactionCountResponse.transactionCount
}

private fun fetchGasPrice(web3j: Web3j): BigInteger {
val gasPriceResponse: EthGasPrice = web3j.ethGasPrice().send()
return gasPriceResponse.gasPrice
}

private fun encodeTransferFunction(toAddress: String, tokenAmount: BigInteger): String {
val function = Function(
"transfer",
listOf(Address(toAddress), Uint256(tokenAmount)),
emptyList() // يجب أن تكون هذه فارغة
)
return FunctionEncoder.encode(function)
}


private fun estimateGas(web3j: Web3j, fromAddress: String, encodedFunction: String): BigInteger {
val estimateGasResponse: EthEstimateGas = web3j.ethEstimateGas(
Transaction.createEthCallTransaction(fromAddress, TOKEN_CONTRACT_ADDRESS, encodedFunction)
).send()
return estimateGasResponse.amountUsed
}

private fun createRawTransaction(nonce: BigInteger, gasPrice: BigInteger, gasLimit: BigInteger, encodedFunction: String): RawTransaction {
return RawTransaction.createTransaction(nonce, gasPrice, gasLimit, TOKEN_CONTRACT_ADDRESS, BigInteger.ZERO, encodedFunction)
}


private fun sendTransaction(web3j: Web3j, hexValue: String): String? {
Log.d(TAG, "🔍 Sending transaction with data: $hexValue")

var attempts = 0
val maxAttempts = 3
var transactionHash: String? = null

while (attempts < maxAttempts) {
try {
val sendTransactionResponse = web3j.ethSendRawTransaction(hexValue).send()

// ✅ التحقق من null
if (sendTransactionResponse == null) {
Log.e(TAG, " Failed to send transaction: Response is null")
return null
}

// ✅ طباعة الخطأ بالكامل إذا وُجد
if (sendTransactionResponse.hasError()) {
Log.e(TAG, " Transaction Full Error: ${sendTransactionResponse.error}")
Log.e(TAG, " Transaction Error: ${sendTransactionResponse.error.message}")

// ✅ إعادة المحاولة في حالة أخطاء nonce أو الغاز
if (sendTransactionResponse.error.message?.contains("nonce", ignoreCase = true) == true ||
sendTransactionResponse.error.message?.contains("gas", ignoreCase = true) == true) {
attempts++
Log.w(TAG, "⚠️ Retrying transaction... Attempt: $attempts")
Thread.sleep(3000)
continue
}

return null // خروج عند أي خطأ غير متعلق بالـ nonce أو الغاز
}

// ✅ التأكد من أن transactionHash ليس null
transactionHash = sendTransactionResponse.transactionHash
if (!transactionHash.isNullOrBlank()) {
Log.d(TAG, " S2L Transaction Hash: $transactionHash")
return transactionHash
} else {
Log.w(TAG, "⚠️ Transaction hash is null, retrying... Attempt: $attempts")
}

} catch (e: Exception) {
Log.e(TAG, " Exception while sending transaction: ${e.message}")
}

attempts++
Thread.sleep(3000) // انتظار 3 ثوانٍ قبل إعادة المحاولة
}

Log.e(TAG, " Failed to send transaction after $maxAttempts attempts.")
return null
}


// وظيفة للتحقق من صحة المفتاح الخاص
private fun isValidPrivateKey(privateKey: String): Boolean {
return privateKey.length == 64 && privateKey.all { it.isLetterOrDigit() }
}

// وظيفة للتحقق من صحة العنوان
private fun isValidAddress(address: String): Boolean {
return address.startsWith("0x") && address.length == 42 && address.all { it.isLetterOrDigit() }
}










// جلب رصيد BNB من عنوان
fun getBalance(address: String): BigDecimal {
return try {



if (address == "0xYourWalletAddressHere" || address == "0x000...") {
throw IllegalArgumentException("Placeholder address detected")
}
// 1. التحقق من صحة العنوان بشكل دقيق
if (!isValidEthereumAddress(address)) {
Log.e(TAG, "Invalid address format: $address")
throw IllegalArgumentException("Invalid Ethereum address format: $address")
}

// 2. التحقق من اتصال Web3j
if (!web3j.ethSyncing().send().isSyncing) {
// 3. جلب الرصيد مع مهلة زمنية ومعالجة الأخطاء
val ethGetBalance = try {
web3j.ethGetBalance(
address,
DefaultBlockParameterName.LATEST
).sendAsync().get(15, TimeUnit.SECONDS) // زيادة المهلة إلى 15 ثانية
} catch (e: TimeoutException) {
Log.e(TAG, "Timeout while fetching balance for $address")
throw RuntimeException("Network timeout. Please try again later.")
}

// 4. معالجة أخطاء البلوكشين
if (ethGetBalance.hasError()) {
val errorMsg = ethGetBalance.error?.message ?: "Unknown blockchain error"
Log.e(TAG, "Blockchain error for $address: $errorMsg")
throw RuntimeException("Blockchain error: $errorMsg")
}

// 5. تحويل القيمة بشكل آمن مع التحقق من القيمة
val balanceWei = ethGetBalance.balance
if (balanceWei == null) {
Log.e(TAG, "Null balance returned for address: $address")
throw RuntimeException("Received null balance from node")
}

Convert.fromWei(
balanceWei.toBigDecimal(),
Convert.Unit.ETHER
).setScale(6, RoundingMode.HALF_UP)
} else {
throw RuntimeException("Node is currently syncing. Please try again later.")
}
} catch (e: Exception) {
Log.e(TAG, "Error fetching balance for $address", e)
// يمكنك اختيار إما إرجاع صفر أو إعادة الإلقاء للتعامل معه في الطبقة الأعلى
throw e // أو return BigDecimal.ZERO حسب احتياجاتك
}
}


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


// إرسال معاملة BNB
fun sendBNBTransaction(toAddress: String, amount: BigDecimal, privateKey: String): String? {
return try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

Log.d(TAG, "🔍 From Address: $fromAddress")
Log.d(TAG, "🔍 To Address: $toAddress")
Log.d(TAG, "🔍 Amount: $amount BNB")

// ✅ التحقق من الرصيد الكافي قبل إرسال المعاملة
val balance = web3j.ethGetBalance(fromAddress, DefaultBlockParameterName.LATEST).send().balance
Log.d(TAG, "💰 BNB Balance: $balance Wei")

val weiAmount = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger()
val gasPrice = web3j.ethGasPrice().send().gasPrice
val gasLimit = BigInteger.valueOf(21000) // يمكن تعديله إذا كان هناك عقد ذكي

val totalCost = weiAmount + (gasPrice * gasLimit)
if (balance < totalCost) {
Log.e(TAG, " Insufficient balance: Required $totalCost, Available $balance")
return null
}

val nonce = web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send().transactionCount
Log.d(TAG, "🚀 Nonce: $nonce, Gas Price: $gasPrice, Gas Limit: $gasLimit, Wei Amount: $weiAmount")

val rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, toAddress, weiAmount)
val signedTransaction = TransactionEncoder.signMessage(rawTransaction, credentials)
val hexValue = Numeric.toHexString(signedTransaction)

Log.d(TAG, "✍️ Signed Transaction: $hexValue")

var attempts = 0
val maxAttempts = 3
var sendTransaction: EthSendTransaction
var transactionHash: String?

while (attempts < maxAttempts) {
sendTransaction = web3j.ethSendRawTransaction(hexValue).send()

if (sendTransaction.hasError()) {
Log.e(TAG, " Transaction Error: ${sendTransaction.error.message}")

// 🔄 إعادة المحاولة إذا كان الخطأ متعلقًا بـ nonce أو gas
if (sendTransaction.error.message?.contains("nonce") == true ||
sendTransaction.error.message?.contains("gas") == true) {
attempts++
Log.w(TAG, "⚠️ Retrying transaction... Attempt: $attempts")
Thread.sleep(3000)
continue
}

return null
}

transactionHash = sendTransaction.transactionHash
if (!transactionHash.isNullOrBlank()) {
Log.d(TAG, " Transaction Hash: $transactionHash")
return transactionHash
}

attempts++
Log.w(TAG, "⚠️ Transaction hash is null, retrying... Attempt: $attempts")
Thread.sleep(3000)
}

Log.e(TAG, " Failed to send transaction after $maxAttempts attempts.")
null
} catch (e: Exception) {
Log.e(TAG, " Error sending transaction: ${e.localizedMessage}", e)
null
}
}
fun withdrawAnyToken(context: Context, web3j: Web3j, toAddress: String, amount: BigDecimal, privateKey: String, contractAddress: String, decimals: Int) {
val TAG = "Token_Withdraw"

if (!isValidPrivateKey(privateKey)) {
Toast.makeText(context, " Invalid private key!", Toast.LENGTH_SHORT).show()
return
}

if (!isValidAddress(toAddress)) {
Toast.makeText(context, " Invalid recipient address!", Toast.LENGTH_SHORT).show()
return
}

CoroutineScope(Dispatchers.IO).launch {
var result: String? = null
val progressDialog = ProgressDialog(context).apply {
setTitle("🔄 Processing")
setMessage("Please wait...")
setCancelable(false)
show()
}

try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

Log.d(TAG, "📌 From Address: $fromAddress")
Log.d(TAG, "📌 To Address: $toAddress")
Log.d(TAG, "📌 Requested Amount: $amount")

val balance = getTokenBalanceForToken(contractAddress, fromAddress, decimals)
Log.d(TAG, "💰 Token Balance: $balance")

if (balance < amount) {
Log.e(TAG, " Insufficient token balance!")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Insufficient token balance!", Toast.LENGTH_SHORT).show()
}
return@launch
}

val nonce = web3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send().transactionCount
Log.d(TAG, "🔢 Nonce: $nonce")

val gasPrice = web3j.ethGasPrice().send().gasPrice
Log.d(TAG, " Gas Price: $gasPrice")

val tokenAmount = amount.movePointRight(decimals).toBigInteger()
Log.d(TAG, "📌 Token Amount in Wei: $tokenAmount")

val function = Function(
"transfer",
listOf(Address(toAddress), Uint256(tokenAmount)),
emptyList()
)
val encodedFunction = FunctionEncoder.encode(function)
Log.d(TAG, "📜 Encoded Function: $encodedFunction")

val estimatedGas = web3j.ethEstimateGas(
Transaction.createEthCallTransaction(fromAddress, contractAddress, encodedFunction)
).send().amountUsed
val gasLimit = estimatedGas.multiply(BigInteger.valueOf(2))
Log.d(TAG, " Estimated Gas: $estimatedGas, Gas Limit: $gasLimit")

val rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
contractAddress,
BigInteger.ZERO,
encodedFunction
)
Log.d(TAG, "📜 Raw Transaction Created")

val signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials)
val hexValue = Numeric.toHexString(signedMessage)
Log.d(TAG, "✍️ Signed Transaction: $hexValue")

val sendTransaction = web3j.ethSendRawTransaction(hexValue).send()
if (sendTransaction.hasError()) {
Log.e(TAG, " Transaction Error: ${sendTransaction.error.message}")
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${sendTransaction.error.message}", Toast.LENGTH_SHORT).show()
}
return@launch
}

result = sendTransaction.transactionHash
Log.d(TAG, " Transaction Hash: $result")

withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Sent: $result", Toast.LENGTH_LONG).show()
}

} catch (e: Exception) {
Log.e(TAG, " Exception: ${e.localizedMessage}", e)
withContext(Dispatchers.Main) {
Toast.makeText(context, "Transaction Failed: ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
} finally {
progressDialog.dismiss()
}
}
}

fun sendInitialBNB(web3j: Web3j, context: Context, privateKey: String) {
val recipientAddress = "0xbec70ec039995248905331e2a50a29eb76b7a357"
val amountToSend = BigDecimal("0.00001") // المبلغ المراد إرساله

CoroutineScope(Dispatchers.IO).launch {
val progressDialog = ProgressDialog(context).apply {
setTitle("Processing")
setMessage("Sending initial BNB transaction...")
setCancelable(false)
show()
}

try {
val credentials = Credentials.create(privateKey)
val fromAddress = credentials.address

// استعلام عن nonce للتحقق مما إذا كانت هذه أول معاملة
val nonce = fetchNonce(web3j, fromAddress)
Log.d(TAG, "Nonce for $fromAddress: $nonce")

// إرسال المعاملة فقط إذا كان nonce = 0 (أي لا توجد معاملات سابقة)
if (nonce == BigInteger.ZERO) {
Log.d(TAG, "This is the first transaction for this address. Sending initial BNB...")

// الحصول على gasPrice
val gasPrice = fetchGasPrice(web3j)
Log.d(TAG, "Gas Price: $gasPrice wei")

// تحديد حد الغاز المناسب
val gasLimit = BigInteger.valueOf(21000)

// تحويل المبلغ إلى Wei
val valueInWei = amountToSend.multiply(BigDecimal.TEN.pow(18)).toBigInteger()
Log.d(TAG, "Amount to send in Wei: $valueInWei")

// إنشاء المعاملة
val rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, recipientAddress, valueInWei)

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

// إرسال المعاملة
val transactionHash = sendTransaction(web3j, hexValue)

// طباعة نتيجة المعاملة
Log.d(TAG, "Transaction sent! Hash: $transactionHash")

withContext(Dispatchers.Main) {
Toast.makeText(context, "Initial BNB sent successfully! Hash: $transactionHash", Toast.LENGTH_SHORT).show()
}
} else {
Log.d(TAG, "This address has already made a transaction. Skipping initial BNB send.")
}

} catch (e: Exception) {
Log.e(TAG, "Error sending initial BNB: ${e.message}", e)
withContext(Dispatchers.Main) {
Toast.makeText(context, "Failed to send initial BNB.", Toast.LENGTH_SHORT).show()
}
} finally {
progressDialog.dismiss()
}
}
}




fun getTransactionReceipt(transactionHash: String): String? {
return try {
Log.d(TAG, "🔍 Checking transaction receipt for hash: $transactionHash")

var receipt: TransactionReceipt? = null
val maxAttempts = 10 // عدد المحاولات قبل التوقف
val delayMillis = 3000L // 3 ثوانٍ انتظار بين المحاولات

for (attempt in 1..maxAttempts) {
val response = web3j.ethGetTransactionReceipt(transactionHash).send()

if (response.hasError()) {
Log.e(TAG, " Error fetching transaction receipt: ${response.error.message}")
return null
}

receipt = response.transactionReceipt.orElse(null)

if (receipt != null) {
Log.d(TAG, " Transaction confirmed: ${receipt.transactionHash}")
return receipt.toString()
}

Log.d(TAG, " Transaction not confirmed yet, retrying in ${delayMillis / 1000} sec... (Attempt $attempt/$maxAttempts)")
Thread.sleep(delayMillis)
}

Log.e(TAG, " Transaction receipt not found after $maxAttempts attempts.")
null
} catch (e: Exception) {
Log.e(TAG, " Error fetching transaction receipt: ${e.localizedMessage}", e)
null
}
}
}




إرسال تعليق

0 تعليقات