using Microsoft.Extensions.Logging; using System; using System.Net.Http; using System.Numerics; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Transactions; using TronNet; using TronNet.Accounts; using WpfApp1TRC20.Data; using TransactionStatus = WpfApp1TRC20.Data.TransactionStatus; namespace WpfApp1TRC20.Services { public class TronService : ITronService { private readonly ITronClient _tronClient; private readonly ILogger _logger; private const string TRON_MAINNET = "https://api.trongrid.io"; private const string TRON_TESTNET = "https://api.shasta.trongrid.io"; public TronService(ILogger logger) { _logger = logger; // Use testnet for development, mainnet for production var httpClient = new HttpClient(); _tronClient = new TronClient(httpClient, TRON_TESTNET); } public async Task CreateTokenAsync(TokenCreationParams parameters, string ownerPrivateKey) { try { var account = new TronAccount(ownerPrivateKey); // Compile and deploy the smart contract var contractData = CompileContract(parameters); var transaction = await _tronClient.CreateTransactionAsync( account.Address, contractData, 0, "Smart Contract Creation" ); var signedTransaction = transaction.Sign(account); var result = await _tronClient.BroadcastTransactionAsync(signedTransaction); _logger.LogInformation($"Token creation transaction broadcast: {result.Txid}"); return result.Txid; } catch (Exception ex) { _logger.LogError(ex, "Error creating token"); throw; } } public async Task TransferTokenAsync(string contractAddress, string fromPrivateKey, string toAddress, decimal amount) { try { var fromAccount = new TronAccount(fromPrivateKey); // Check if token is expired first if (await IsTokenExpiredAsync(contractAddress)) { throw new InvalidOperationException("Token has expired and cannot be transferred"); } var contract = _tronClient.GetContract(contractAddress); var transferFunction = contract.GetFunction("transfer"); var transaction = await transferFunction.CreateTransactionAsync( fromAccount.Address, toAddress, (BigInteger)(amount * (decimal)Math.Pow(10, 18)) // Assuming 18 decimals ); var signedTransaction = transaction.Sign(fromAccount); var result = await _tronClient.BroadcastTransactionAsync(signedTransaction); _logger.LogInformation($"Token transfer transaction broadcast: {result.Txid}"); return result.Txid; } catch (Exception ex) { _logger.LogError(ex, "Error transferring tokens"); throw; } } public async Task GetTokenBalanceAsync(string contractAddress, string address) { try { var contract = _tronClient.GetContract(contractAddress); var balanceFunction = contract.GetFunction("balanceOf"); var balance = await balanceFunction.CallAsync(address); return (decimal)balance / (decimal)Math.Pow(10, 18); // Assuming 18 decimals } catch (Exception ex) { _logger.LogError(ex, "Error getting token balance"); return 0; } } public async Task GetTrxBalanceAsync(string address) { try { var account = await _tronClient.GetAccountAsync(address); return (decimal)account.Balance / 1_000_000; // TRX has 6 decimals } catch (Exception ex) { _logger.LogError(ex, "Error getting TRX balance"); return 0; } } public async Task GetTransactionAsync(string txHash) { try { var transaction = await _tronClient.GetTransactionByIdAsync(txHash); var transactionInfo = await _tronClient.GetTransactionInfoByIdAsync(txHash); return new TransactionRecord { TransactionHash = txHash, Status = transactionInfo.Receipt.Result == "SUCCESS" ? TransactionStatus.Confirmed : TransactionStatus.Failed, Timestamp = DateTimeOffset.FromUnixTimeMilliseconds(transaction.RawData.Timestamp).DateTime, GasFee = (decimal)transactionInfo.Fee / 1_000_000 }; } catch (Exception ex) { _logger.LogError(ex, "Error getting transaction info"); throw; } } public async Task IsTokenExpiredAsync(string contractAddress) { try { var contract = _tronClient.GetContract(contractAddress); var isExpiredFunction = contract.GetFunction("isExpired"); var isExpired = await isExpiredFunction.CallAsync(); return isExpired; } catch (Exception ex) { _logger.LogError(ex, "Error checking token expiry"); return false; } } public WalletAccount CreateWallet(string name) { var account = TronAccount.GenerateAccount(); return new WalletAccount { Name = name, Address = account.Address, EncryptedPrivateKey = EncryptPrivateKey(account.PrivateKey), CreatedDate = DateTime.UtcNow, IsImported = false }; } public WalletAccount ImportWallet(string name, string privateKey) { try { var account = new TronAccount(privateKey); return new WalletAccount { Name = name, Address = account.Address, EncryptedPrivateKey = EncryptPrivateKey(privateKey), CreatedDate = DateTime.UtcNow, IsImported = true }; } catch (Exception ex) { _logger.LogError(ex, "Error importing wallet"); throw new ArgumentException("Invalid private key"); } } public string DecryptPrivateKey(string encryptedPrivateKey) { try { var encryptedBytes = Convert.FromBase64String(encryptedPrivateKey); var decryptedBytes = ProtectedData.Unprotect( encryptedBytes, null, DataProtectionScope.CurrentUser ); return Encoding.UTF8.GetString(decryptedBytes); } catch (Exception ex) { _logger.LogError(ex, "Error decrypting private key"); throw; } } private string EncryptPrivateKey(string privateKey) { var dataBytes = Encoding.UTF8.GetBytes(privateKey); var encryptedBytes = ProtectedData.Protect( dataBytes, null, DataProtectionScope.CurrentUser ); return Convert.ToBase64String(encryptedBytes); } private string CompileContract(TokenCreationParams parameters) { // In a real implementation, you would use a Solidity compiler // For now, we'll use pre-compiled bytecode with constructor parameters // This is a simplified approach - in production, use tools like Nethereum.Contracts var constructorParams = EncodeConstructorParameters( parameters.Name, parameters.Symbol, (byte)parameters.Decimals, parameters.TotalSupply, parameters.ExpiryDays ); return TRC20TokenManager.Contracts.TimedTRC20Contract.Bytecode + constructorParams; } private string EncodeConstructorParameters(string name, string symbol, byte decimals, decimal totalSupply, int expiryDays) { // Simplified ABI encoding - in production use proper ABI encoding library // This would need to be implemented properly using ABI encoding standards return ""; } } }