// ignore_for_file: depend_on_referenced_packages import 'dart:typed_data'; import 'package:flutter_wallet/tools/YSNetWork.dart'; import 'package:flutter_wallet/tools/YSTools.dart'; import 'package:web3dart/web3dart.dart'; import 'dart:math'; import 'package:http/http.dart'; import 'package:intl/intl.dart'; import 'dart:convert'; import 'package:flutter/services.dart' show rootBundle; const int ysdecimals = 18; class Wbe3Api { late Wbe3Api? wbe3api; late Web3Client? client = Web3Client(YSData().rpc, Client()); late DeployedContract contract; late String _contractAddress; late int decimals = 18; //使用单例模式, Future getInstances() async { try { wbe3api = Wbe3Api(); client = Web3Client(YSData().rpc, Client()); return wbe3api; } catch (error) { LogUtil.d(error); return null; } } //获取主链余额 static Future getBalance(String address) async { try { final client = Web3Client(YSData().rpc, Client()); EtherAmount? amount = await client.getBalance(EthereumAddress.fromHex(address)); BigInt? available = amount.getInWei; String blance = (available/ BigInt.from(pow(10, ysdecimals))).toString(); LogUtil.d("$address=====$blance"); await client.dispose(); return blance; } catch (err) { LogUtil.d(' 余额错误: ${err.toString()}'); return '0.0'; } } //获取主链矿工费,如果矿工费给的不够高,那就无法交易 Future getdefaultEthfee() async { EtherAmount? gasprice = await client?.getGasPrice(); LogUtil.d("==${_tofee(BigInt.from(21000), gasprice!)}"); return _tofee(BigInt.from(21000), gasprice); } /// 获取手续费 /// gaslimit :最小gas,合约需要算出来,主链币则默认为21000 /// gasprice:gas价格 String _tofee(BigInt gaslimit, EtherAmount gasprice) { var fee = gaslimit * gasprice.getInWei; var result = fee / BigInt.from(pow(10, ysdecimals)); return result.toString(); } //判断以太坊地址是否正确 Future getIsGCAddress(String maddress) async { try {// EthereumAddress address = EthereumAddress.fromHex(maddress); LogUtil.d(address); return true; } catch (e) { return false; } } /// 发起普通交易 /// fromaddress 发送地址 /// toaddress 接收地址 /// privatekey 私钥 /// fee 手续费 /// value 数量 Future signETHTransaction(String fromaddress, String toaddress, String privatekey, String value,String gas,{Uint8List? data,String? fee}) async { // LogUtil.d('发送地址:$fromaddress\n接收地址:$toaddress\n金额:$value\n服务费:$gas'); try { // LogUtil.d(YSData().rpc); final credentials = EthPrivateKey.fromHex(privatekey); // EthereumAddress from = EthereumAddress.fromHex(fromaddress); final receiver = EthereumAddress.fromHex(toaddress); // EtherAmount? gasprice = await client?.getGasPrice(); EtherAmount? gasprice = await client?.getGasPrice(); if(fee!=null){ gasprice = EtherAmount.fromInt(EtherUnit.wei,int.parse(fee)); } BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0)); final networkId = await client?.getNetworkId(); BigInt amount = tokenInt(value, decimals); EtherAmount amountValue = EtherAmount.fromBigInt(EtherUnit.wei, amount); if(value=='0'){ amountValue = EtherAmount.fromInt(EtherUnit.wei,0); } // BigInt gaslimit = BigInt.from(double.parse(fee)* pow(10, decimals)); // LogUtil.d( // '发送地址:$fromaddress\n' // '接收地址:$toaddress\n' // '金额:${EtherAmount.fromBigInt(EtherUnit.wei, amount)}\n' // 'gasPrice:$gasprice\n' // 'maxGas:${gaslimit.toInt()}' // ); var transaction = data!=null?Transaction( to: receiver, gasPrice: gasprice, maxGas: gaslimit.toInt(), value: amountValue, data: data ):Transaction( to: receiver, gasPrice: gasprice, maxGas: gaslimit.toInt(), value: amountValue, ); var txHash = await client?.sendTransaction( credentials, transaction, chainId: networkId, ); LogUtil.d('transferhash====${txHash??''}'); await client?.dispose(); return txHash; } catch (error) { LogUtil.d(error); ysFlutterToast('$error'); return ''; } } /// 通过精度格式化 传入的数量 /// value 数量 /// decimals 精度(保留小数位) BigInt tokenInt(String? value, int decimals) { if (value==null) { return BigInt.zero; } double? v = 0; try { if (value.contains(',') || value.contains('.')) { v = NumberFormat(",##0.${"0" * decimals}").parse(value) as double?; } else { v = double.parse(value); } } catch (err) { LogUtil.d('Fmt.tokenInt() error: ${err.toString()}'); } return BigInt.from(v! * pow(10, decimals)); } /// 判断是否合约地址 /// contractaddress 合约地址 Future getIsContractAddress(String contractaddress) async { if (contractaddress.length != 42) { return false; } else { EthereumAddress address = EthereumAddress.fromHex(contractaddress); var respons = await client?.getCode(address); LogUtil.d("respons ====$respons"); return respons!.isNotEmpty ? true : false; } } /// 设置全局合约,读取abi Future setContaract(String contractaddress,{int decimal = 0}) async { _contractAddress = contractaddress; contract = await fromAssets('images/contract.json', _contractAddress); // decimals = decimal; // LogUtil.d(_contractAddress); // decimals = decimal; // return true; // LogUtil.d('setContaract=========$_contractAddress'); var result = await getContractInfo('decimals'); if('$result'.contains('RangeError')){ decimals = decimal; return true; }else{ var result = await getContractInfo('decimals'); decimals = int.parse(result.toString()); return true; } return false; } /// 将合约格式化 Future fromAssets(String path, String contractAddress) async { final contractJson = jsonDecode(await rootBundle.loadString(path)); DeployedContract value = DeployedContract(ContractAbi.fromJson(jsonEncode(contractJson['abi']),contractJson['contractName'] as String),EthereumAddress.fromHex(contractAddress)); return value; } /// 读取合约基本信息decimals和symbol adppContaractDecimals(String contractaddress) async { // int dappDecimals = 18; _contractAddress = contractaddress; contract = await fromAssets('images/contract.json', _contractAddress); decimals = 0; // try { // contract = await fromAssets('images/contract.json', contractaddress); // var dec = await getContractInfo('decimals'); // var type = await getContractInfo('symbol'); // decimals = int.parse(dec.toString()); // LogUtil.d("adpp精度获取==$decimals"); // return {'decimals': decimals, 'coin': type}; // } catch (error) { // return {'decimals': decimals, 'coin': "ETH"}; // } } /// 获取合约基本信息 /// functionname 方法名 /// decimals:合约精度,小数位 /// name 名字 /// symbol 和名字一致 Future getContractInfo(String functionname) async { try { final response = await client?.call( contract: contract, function: contract.function(functionname), params: [], ); // LogUtil.d('getContractInfo${response?.first.toString()}'); return response?.first.toString(); } catch (error) { // LogUtil.d('getContractInfo2$error'); return error.toString(); } } //获取合约余额 Future getTokenBalance(String madress,String contractAddress) async { // LogUtil.d(YSData().rpc); bool isCheck = await setContaract(contractAddress); if(isCheck){ EthereumAddress adress = EthereumAddress.fromHex(madress); final response = await client?.call( contract: contract, function: contract.function('balanceOf'), params: [adress], ); // LogUtil.d('response=====${contract.address}'); // LogUtil.d(response.toString()); double blanceD = response?.first / BigInt.from(pow(10, decimals)); // String blance = blanceD.toStringAsFixed(10); LogUtil.d('$madress====$blanceD'); return '$blanceD'; } return '0.0'; } //转出手续费 Future getTransferFee( String fromaddress, String toaddress, String value) async { BigInt amount = tokenInt(value, decimals); EthereumAddress receiver = EthereumAddress.fromHex(toaddress); return await getCommonFee(fromaddress, "transfer", [receiver, amount]); } //兑换手续费 Future getexchangeFee(String fromaddress, String toaddress, String value) async { BigInt amount = tokenInt(value, decimals); return await getCommonFee(fromaddress, "exchange", [amount]); } /* * 获取合约手续费通用方法 * fromaddress 发送地址 * functionname 方法名 * parameters 合约参数 */ Future getCommonFee( String from, String functionname, List parameters) async { EthereumAddress fromaddress = EthereumAddress.fromHex(from); final gasprice = await client?.getGasPrice(); LogUtil.d('gasprice$gasprice'); var transaction = Transaction.callContract( contract: contract, function: contract.function(functionname), parameters: parameters, gasPrice: gasprice, from: fromaddress); BigInt? gaslimit = BigInt.from(21000); LogUtil.d('检测gaslimit${transaction.data} $gaslimit'); try { LogUtil.d("gaslimit ====${transaction.from}====${transaction.to}====${transaction.data}====${EtherAmount.zero()}"); gaslimit = await client?.estimateGas( sender: transaction.from, to: transaction.to, data: transaction.data, value: EtherAmount.zero() ); // gaslimit = await client?.estimateGas( // sender: fromaddress, // to: EthereumAddress.fromHex(_contractAddress), // data: transaction.data, // value: EtherAmount.zero()); LogUtil.d('gaslimit ====$gaslimit'); return _tofee(gaslimit!, gasprice!); } catch (error) { LogUtil.d(error.toString()); return 'error$error'; } } /// 发起合约转账 /// fromaddress 发送地址 /// toaddress 接收地址 /// privatekey 私钥 /// value 数量 Future tokenTransfer(String fromaddress, String toaddress, String privatekey, String fee, String value,String gas) async { LogUtil.d('发送地址:$fromaddress\n接收地址:$toaddress\n金额:$value\n服务费:$fee'); BigInt amount = tokenInt(value, decimals); EthereumAddress receiver = EthereumAddress.fromHex(toaddress); return await signContractTransaction2(fromaddress, privatekey, fee, "transfer", [receiver, amount],gas); } Future tokenTransfer2(String fromaddress, String toaddress, String privatekey, String fee, String value,String gas) async { LogUtil.d('发送地址:$fromaddress\n接收地址:$toaddress\n金额:$value\n服务费:$fee'); BigInt amount = tokenInt(value, decimals); EthereumAddress receiver = EthereumAddress.fromHex(toaddress); return await signContractTransaction3(fromaddress, privatekey, fee, "transfer", [receiver, amount],gas); } /// 发起兑换交易 /// fromaddress 发送地址 /// privatekey 私钥 /// value 数量 Future tokenExchange(String fromaddress, String privatekey, String fee, String value, String gas,String toaddress,String rpc,String towalletaddress,String fromtokenaddress) async { BigInt amount = tokenInt(value, decimals); // LogUtil.d(contract.address.hexEip55); // String changeStr = await getexchangeFee(fromaddress, contract.address.hexEip55, value); // LogUtil.d(changeStr); // return ''; // return await signContractTransaction3(fromaddress, privatekey, fee, "exchange", [amount],gas); LogUtil.d('tokenExchange============$fromaddress===============$toaddress'); bool isContract = await getIsContractAddress(fromtokenaddress); bool isWBNB = toaddress=='0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'&&isContract==false; // final myAddress = EthereumAddress.fromHex(fromaddress); final toWalletAddress = EthereumAddress.fromHex(towalletaddress); // 要交换的代币合约地址,例如:CAKE final tokenIn = EthereumAddress.fromHex(isContract?fromtokenaddress:'0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'); // 要接收的代币合约地址,例如:USDT final tokenOut = EthereumAddress.fromHex(toaddress); client = Web3Client(rpc, Client()); contract = await fromAssets('asset/exchange.json', isWBNB?'0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c':YSData().pancakeAddress); //swapExactETHForTokens swapExactTokensForTokens String funName = 'swapExactETHForTokens'; if(isContract){ funName = 'swapExactTokensForTokens'; } if(isWBNB){ funName = 'deposit'; } List parameters = isWBNB?[]:[ amount, // 要交换的代币数量(注意小数位数) if(funName=='swapExactTokensForTokens')BigInt.from(0), // 接收的最少代币数量 funName=='swapExactTokensForTokens'?[tokenIn, tokenOut]:[tokenIn,tokenOut], // 路径 toWalletAddress, // 接收地址 BigInt.from((DateTime.now().millisecondsSinceEpoch / 1000).floor() + 60 * 20), // 截止时间 ]; LogUtil.d('tokenExchange=======$funName======$isContract====$parameters'); return await signContractTransaction4(fromaddress, privatekey, fee, funName,parameters ,gas,amount: (isContract==false)?amount:null); } /* * 发起合约交易 * fromaddress 发送地址 * privatekey 私钥 * functionname 合約调用用方法 * parameters 合約参數 */ Future signContractTransaction4(String from, String privatekey,String fee, String functionname, List parameters, String gas,{BigInt? amount}) async { // bool isCheck = await setContaract(YSData().contAddress); LogUtil.d('amount======$amount'); if(true){ try { final credentials = EthPrivateKey.fromHex(privatekey); EthereumAddress fromaddress = EthereumAddress.fromHex(from); final networkId = await client?.getNetworkId(); final gasprice = await client?.getGasPrice(); // LogUtil.d(gasprice); // 设置交易参数 final transaction = Transaction.callContract( contract: contract, function: contract.function(functionname), parameters: parameters, from: fromaddress, gasPrice: gasprice, maxGas: 200000, value: amount==null?EtherAmount.zero():EtherAmount.inWei(amount), ); // return ''; var txHash = await client?.sendTransaction( credentials, transaction, chainId: networkId, ); LogUtil.d('hash====${txHash!}'); await client?.dispose(); return txHash; } catch (error) { LogUtil.d('signContractTransaction error========$error'); ysFlutterToast('$error'); return ''; } } return ''; } Future signContractTransaction(String from, String privatekey,String fee, String functionname, List parameters, String gas) async { // bool isCheck = await setContaract(YSData().contAddress); LogUtil.d('decimals======$decimals'); if(true){ try { EthereumAddress fromaddress = EthereumAddress.fromHex(from); final credentials = EthPrivateKey.fromHex(privatekey); final networkId = await client?.getNetworkId(); final gasprice = await client?.getGasPrice(); BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0)); // LogUtil.d('decimals======${gaslimit.toInt()}'); // BigInt feeValue = BigInt.from(double.parse(fee) * pow(10, decimals)); LogUtil.d("gaslimit ====${gaslimit.toInt()}\n$parameters\n$gasprice"); var transaction = Transaction.callContract( contract: contract, function: contract.function(functionname), parameters: parameters, from: fromaddress, gasPrice: gasprice, maxGas: gaslimit.toInt()); var txHash = await client?.sendTransaction( credentials, transaction, chainId: networkId, ); LogUtil.d('hash====${txHash!}'); await client?.dispose(); return txHash; } catch (error) { LogUtil.d('signContractTransaction error========$error'); ysFlutterToast('$error'); return ''; } } return ''; } Future signContractTransaction2(String from, String privatekey,String fee, String functionname, List parameters, String gas) async { // bool isCheck = await setContaract(YSData().contAddress); LogUtil.d('decimals======$decimals'); if(true){ try { EthereumAddress fromaddress = EthereumAddress.fromHex(from); final credentials = EthPrivateKey.fromHex(privatekey); final networkId = await client?.getNetworkId(); final gasprice = EtherAmount.fromInt(EtherUnit.wei,int.parse(fee)); BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0)); // LogUtil.d('decimals======${gaslimit.toInt()}'); // BigInt feeValue = BigInt.from(double.parse(fee) * pow(10, decimals)); LogUtil.d("gaslimit ====${gaslimit.toInt()}\n$parameters\n$gasprice"); var transaction = Transaction.callContract( contract: contract, function: contract.function(functionname), parameters: parameters, from: fromaddress, gasPrice: gasprice, maxGas: gaslimit.toInt()); var txHash = await client?.sendTransaction( credentials, transaction, chainId: networkId, ); LogUtil.d('hash====${txHash!}'); await client?.dispose(); return txHash; } catch (error) { LogUtil.d('signContractTransaction error========$error'); ysFlutterToast('$error'); return ''; } } return ''; } Future signContractTransaction3(String from, String privatekey,String fee, String functionname, List parameters, String gas) async { // bool isCheck = await setContaract(YSData().contAddress); LogUtil.d('decimals======$decimals'); if(true){ try { EthereumAddress fromaddress = EthereumAddress.fromHex(from); final credentials = EthPrivateKey.fromHex(privatekey); final networkId = await client?.getNetworkId(); final gasprice = EtherAmount.fromInt(EtherUnit.wei,int.parse(fee)); BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0)); // LogUtil.d('decimals======${gaslimit.toInt()}'); // BigInt feeValue = BigInt.from(double.parse(fee) * pow(10, decimals)); LogUtil.d("gaslimit ====${gaslimit.toInt()}\n$parameters\n$gasprice"); var transaction = Transaction.callContract( contract: contract, function: contract.function(functionname), parameters: parameters, from: fromaddress, gasPrice: gasprice, maxGas: gaslimit.toInt()); LogUtil.d(YSData().rpc); LogUtil.d(transaction.data); return ''; var txHash = await client?.sendTransaction( credentials, transaction, chainId: networkId, ); LogUtil.d('hash====${txHash!}'); await client?.dispose(); return txHash; } catch (error) { LogUtil.d('signContractTransaction error========$error'); ysFlutterToast('$error'); return ''; } } return ''; } /// 获取交易状态 /// txHash 交易hash Future getTranferstate(String txHash) async { try { var transactionReceipt = await client?.getTransactionReceipt(txHash); if (transactionReceipt != null) { LogUtil.d("交易状态: ${transactionReceipt.status}"); await client?.dispose(); return transactionReceipt.status; } return false; } catch (error) { LogUtil.d("状态error: $error"); return false; } } } //格式化小数点 String formatFour(String values) { double value = double.tryParse(values)! / pow(10, ysdecimals); String newvalue = value.toStringAsFixed(8); return newvalue.substring(0, newvalue.indexOf('.') + 7); }