import 'package:dio/dio.dart'; import '../config/app_config.dart'; /// Tron FullNode HTTP API(与 Web TronWeb transactionBuilder 调用的 REST 一致) class TronFullNodeClient { TronFullNodeClient._(); static Dio _dio(String rpcBase) { final base = _normalizeBase(rpcBase); final headers = { 'accept': 'application/json', 'content-type': 'application/json', }; final key = AppConfig.tronGridApiKey.trim(); if (key.isNotEmpty) { headers['TRON-PRO-API-KEY'] = key; } return Dio( BaseOptions( baseUrl: base, connectTimeout: const Duration(seconds: 25), receiveTimeout: const Duration(seconds: 25), headers: headers, ), ); } static String _normalizeBase(String rpcUrl) { var u = rpcUrl.trim(); if (u.endsWith('/')) { u = u.substring(0, u.length - 1); } return u; } /// POST `/wallet/triggersmartcontract` static Future> triggerSmartContract({ required String rpcBase, required String ownerAddressBase58, required String contractAddressBase58, required String functionSelector, required String parameterHex, int feeLimitSun = 150000000, }) async { final dio = _dio(rpcBase); final res = await dio.post( '/wallet/triggersmartcontract', data: { 'owner_address': ownerAddressBase58, 'contract_address': contractAddressBase58, 'function_selector': functionSelector, 'parameter': parameterHex, 'fee_limit': feeLimitSun, 'call_value': 0, 'visible': true, }, ); final body = res.data; if (body is! Map) { throw StateError(' triggersmartcontract 响应无效'); } final map = Map.from(body); final result = map['result']; if (result is Map && result['result'] != true) { throw StateError( result['message']?.toString() ?? '构建 TRC20 交易失败', ); } final tx = map['transaction']; if (tx is! Map) { throw StateError('无 transaction 字段'); } // 与 Reown AppKit 示例一致:WalletConnect `tron_signTransaction` 的 `transaction` // 常期望为 triggersmartcontract 整段 JSON(含 result / transaction 等),不单是内层 tx。 return map; } /// POST `/wallet/createtransaction`(原生 TRX) static Future> createTrxTransaction({ required String rpcBase, required String ownerAddressBase58, required String toAddressBase58, required int amountSun, }) async { final dio = _dio(rpcBase); final res = await dio.post( '/wallet/createtransaction', data: { 'owner_address': ownerAddressBase58, 'to_address': toAddressBase58, 'amount': amountSun, 'visible': true, }, ); final body = res.data; if (body is! Map) { throw StateError('createtransaction 响应无效'); } return Map.from(body); } /// POST `/wallet/broadcasttransaction` static Future broadcastTransaction({ required String rpcBase, required Map signed, }) async { final dio = _dio(rpcBase); final res = await dio.post( '/wallet/broadcasttransaction', data: signed, ); final body = res.data; if (body is! Map) { throw StateError('broadcast 响应无效'); } final map = Map.from(body); final ok = map['result'] == true; final txid = map['txid']?.toString(); if (!ok || txid == null || txid.isEmpty) { throw StateError(map['message']?.toString() ?? '广播交易失败'); } return txid; } }