YSBip2.dart 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // ignore_for_file: depend_on_referenced_packages
  2. import 'dart:typed_data';
  3. import 'package:flutter_wallet/tools/YSNetWork.dart';
  4. import 'package:flutter_wallet/tools/YSTools.dart';
  5. import 'package:web3dart/web3dart.dart';
  6. import 'dart:math';
  7. import 'package:http/http.dart';
  8. import 'package:intl/intl.dart';
  9. import 'dart:convert';
  10. import 'package:flutter/services.dart' show rootBundle;
  11. const int ysdecimals = 18;
  12. class Wbe3Api {
  13. late Wbe3Api? wbe3api;
  14. late Web3Client? client = Web3Client(YSData().rpc, Client());
  15. late DeployedContract contract;
  16. late String _contractAddress;
  17. late int decimals = 18;
  18. //使用单例模式,
  19. Future<Wbe3Api?> getInstances() async {
  20. try {
  21. wbe3api = Wbe3Api();
  22. client = Web3Client(YSData().rpc, Client());
  23. return wbe3api;
  24. } catch (error) {
  25. LogUtil.d(error);
  26. return null;
  27. }
  28. }
  29. //获取主链余额
  30. static Future<String> getBalance(String address) async {
  31. try {
  32. final client = Web3Client(YSData().rpc, Client());
  33. EtherAmount? amount =
  34. await client.getBalance(EthereumAddress.fromHex(address));
  35. BigInt? available = amount.getInWei;
  36. String blance = (available/ BigInt.from(pow(10, ysdecimals))).toString();
  37. LogUtil.d("$address=====$blance");
  38. await client.dispose();
  39. return blance;
  40. } catch (err) {
  41. LogUtil.d(' 余额错误: ${err.toString()}');
  42. return '0.0';
  43. }
  44. }
  45. //获取主链矿工费,如果矿工费给的不够高,那就无法交易
  46. Future<String> getdefaultEthfee() async {
  47. EtherAmount? gasprice = await client?.getGasPrice();
  48. LogUtil.d("==${_tofee(BigInt.from(21000), gasprice!)}");
  49. return _tofee(BigInt.from(21000), gasprice);
  50. }
  51. /// 获取手续费
  52. /// gaslimit :最小gas,合约需要算出来,主链币则默认为21000
  53. /// gasprice:gas价格
  54. String _tofee(BigInt gaslimit, EtherAmount gasprice) {
  55. var fee = gaslimit * gasprice.getInWei;
  56. var result = fee / BigInt.from(pow(10, ysdecimals));
  57. return result.toString();
  58. }
  59. //判断以太坊地址是否正确
  60. Future<bool> getIsGCAddress(String maddress) async {
  61. try {//
  62. EthereumAddress address = EthereumAddress.fromHex(maddress);
  63. LogUtil.d(address);
  64. return true;
  65. } catch (e) {
  66. return false;
  67. }
  68. }
  69. /// 发起普通交易
  70. /// fromaddress 发送地址
  71. /// toaddress 接收地址
  72. /// privatekey 私钥
  73. /// fee 手续费
  74. /// value 数量
  75. Future<Object?> signETHTransaction(String fromaddress, String toaddress,
  76. String privatekey, String value,String gas,{Uint8List? data,String? fee}) async {
  77. // LogUtil.d('发送地址:$fromaddress\n接收地址:$toaddress\n金额:$value\n服务费:$gas');
  78. try {
  79. // LogUtil.d(YSData().rpc);
  80. final credentials = EthPrivateKey.fromHex(privatekey);
  81. // EthereumAddress from = EthereumAddress.fromHex(fromaddress);
  82. final receiver = EthereumAddress.fromHex(toaddress);
  83. // EtherAmount? gasprice = await client?.getGasPrice();
  84. EtherAmount? gasprice = await client?.getGasPrice();
  85. if(fee!=null){
  86. gasprice = EtherAmount.fromInt(EtherUnit.wei,int.parse(fee));
  87. }
  88. BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0));
  89. final networkId = await client?.getNetworkId();
  90. BigInt amount = tokenInt(value, decimals);
  91. EtherAmount amountValue = EtherAmount.fromBigInt(EtherUnit.wei, amount);
  92. if(value=='0'){
  93. amountValue = EtherAmount.fromInt(EtherUnit.wei,0);
  94. }
  95. // BigInt gaslimit = BigInt.from(double.parse(fee)* pow(10, decimals));
  96. // LogUtil.d(
  97. // '发送地址:$fromaddress\n'
  98. // '接收地址:$toaddress\n'
  99. // '金额:${EtherAmount.fromBigInt(EtherUnit.wei, amount)}\n'
  100. // 'gasPrice:$gasprice\n'
  101. // 'maxGas:${gaslimit.toInt()}'
  102. // );
  103. var transaction = data!=null?Transaction(
  104. to: receiver,
  105. gasPrice: gasprice,
  106. maxGas: gaslimit.toInt(),
  107. value: amountValue,
  108. data: data
  109. ):Transaction(
  110. to: receiver,
  111. gasPrice: gasprice,
  112. maxGas: gaslimit.toInt(),
  113. value: amountValue,
  114. );
  115. var txHash = await client?.sendTransaction(
  116. credentials,
  117. transaction,
  118. chainId: networkId,
  119. );
  120. LogUtil.d('transferhash====${txHash??''}');
  121. await client?.dispose();
  122. return txHash;
  123. } catch (error) {
  124. LogUtil.d(error);
  125. ysFlutterToast('$error');
  126. return '';
  127. }
  128. }
  129. /// 通过精度格式化 传入的数量
  130. /// value 数量
  131. /// decimals 精度(保留小数位)
  132. BigInt tokenInt(String? value, int decimals) {
  133. if (value==null) {
  134. return BigInt.zero;
  135. }
  136. double? v = 0;
  137. try {
  138. if (value.contains(',') || value.contains('.')) {
  139. v = NumberFormat(",##0.${"0" * decimals}").parse(value) as double?;
  140. } else {
  141. v = double.parse(value);
  142. }
  143. } catch (err) {
  144. LogUtil.d('Fmt.tokenInt() error: ${err.toString()}');
  145. }
  146. return BigInt.from(v! * pow(10, decimals));
  147. }
  148. /// 判断是否合约地址
  149. /// contractaddress 合约地址
  150. Future<bool> getIsContractAddress(String contractaddress) async {
  151. if (contractaddress.length != 42) {
  152. return false;
  153. } else {
  154. EthereumAddress address = EthereumAddress.fromHex(contractaddress);
  155. var respons = await client?.getCode(address);
  156. LogUtil.d("respons ====$respons");
  157. return respons!.isNotEmpty ? true : false;
  158. }
  159. }
  160. /// 设置全局合约,读取abi
  161. Future<bool> setContaract(String contractaddress,{int decimal = 0}) async {
  162. _contractAddress = contractaddress;
  163. contract = await fromAssets('images/contract.json', _contractAddress);
  164. // decimals = decimal;
  165. // LogUtil.d(_contractAddress);
  166. // decimals = decimal;
  167. // return true;
  168. // LogUtil.d('setContaract=========$_contractAddress');
  169. var result = await getContractInfo('decimals');
  170. if('$result'.contains('RangeError')){
  171. decimals = decimal;
  172. return true;
  173. }else{
  174. var result = await getContractInfo('decimals');
  175. decimals = int.parse(result.toString());
  176. return true;
  177. }
  178. return false;
  179. }
  180. /// 将合约格式化
  181. Future<DeployedContract> fromAssets(String path, String contractAddress) async {
  182. final contractJson = jsonDecode(await rootBundle.loadString(path));
  183. DeployedContract value = DeployedContract(ContractAbi.fromJson(jsonEncode(contractJson['abi']),contractJson['contractName'] as String),EthereumAddress.fromHex(contractAddress));
  184. return value;
  185. }
  186. /// 读取合约基本信息decimals和symbol
  187. adppContaractDecimals(String contractaddress) async {
  188. // int dappDecimals = 18;
  189. _contractAddress = contractaddress;
  190. contract = await fromAssets('images/contract.json', _contractAddress);
  191. decimals = 0;
  192. // try {
  193. // contract = await fromAssets('images/contract.json', contractaddress);
  194. // var dec = await getContractInfo('decimals');
  195. // var type = await getContractInfo('symbol');
  196. // decimals = int.parse(dec.toString());
  197. // LogUtil.d("adpp精度获取==$decimals");
  198. // return {'decimals': decimals, 'coin': type};
  199. // } catch (error) {
  200. // return {'decimals': decimals, 'coin': "ETH"};
  201. // }
  202. }
  203. /// 获取合约基本信息
  204. /// functionname 方法名
  205. /// decimals:合约精度,小数位
  206. /// name 名字
  207. /// symbol 和名字一致
  208. Future<String?> getContractInfo(String functionname) async {
  209. try {
  210. final response = await client?.call(
  211. contract: contract,
  212. function: contract.function(functionname),
  213. params: [],
  214. );
  215. // LogUtil.d('getContractInfo${response?.first.toString()}');
  216. return response?.first.toString();
  217. } catch (error) {
  218. // LogUtil.d('getContractInfo2$error');
  219. return error.toString();
  220. }
  221. }
  222. //获取合约余额
  223. Future<String> getTokenBalance(String madress,String contractAddress) async {
  224. // LogUtil.d(YSData().rpc);
  225. bool isCheck = await setContaract(contractAddress);
  226. if(isCheck){
  227. EthereumAddress adress = EthereumAddress.fromHex(madress);
  228. final response = await client?.call(
  229. contract: contract,
  230. function: contract.function('balanceOf'),
  231. params: [adress],
  232. );
  233. // LogUtil.d('response=====${contract.address}');
  234. // LogUtil.d(response.toString());
  235. double blanceD = response?.first / BigInt.from(pow(10, decimals));
  236. // String blance = blanceD.toStringAsFixed(10);
  237. LogUtil.d('$madress====$blanceD');
  238. return '$blanceD';
  239. }
  240. return '0.0';
  241. }
  242. //转出手续费
  243. Future<String> getTransferFee(
  244. String fromaddress, String toaddress, String value) async {
  245. BigInt amount = tokenInt(value, decimals);
  246. EthereumAddress receiver = EthereumAddress.fromHex(toaddress);
  247. return await getCommonFee(fromaddress, "transfer", [receiver, amount]);
  248. }
  249. //兑换手续费
  250. Future<String> getexchangeFee(String fromaddress, String toaddress, String value) async {
  251. BigInt amount = tokenInt(value, decimals);
  252. return await getCommonFee(fromaddress, "exchange", [amount]);
  253. }
  254. /*
  255. * 获取合约手续费通用方法
  256. * fromaddress 发送地址
  257. * functionname 方法名
  258. * parameters 合约参数
  259. */
  260. Future<String> getCommonFee(
  261. String from, String functionname, List<dynamic> parameters) async {
  262. EthereumAddress fromaddress = EthereumAddress.fromHex(from);
  263. final gasprice = await client?.getGasPrice();
  264. LogUtil.d('gasprice$gasprice');
  265. var transaction = Transaction.callContract(
  266. contract: contract,
  267. function: contract.function(functionname),
  268. parameters: parameters,
  269. gasPrice: gasprice,
  270. from: fromaddress);
  271. BigInt? gaslimit = BigInt.from(21000);
  272. LogUtil.d('检测gaslimit${transaction.data} $gaslimit');
  273. try {
  274. LogUtil.d("gaslimit ====${transaction.from}====${transaction.to}====${transaction.data}====${EtherAmount.zero()}");
  275. gaslimit = await client?.estimateGas(
  276. sender: transaction.from,
  277. to: transaction.to,
  278. data: transaction.data,
  279. value: EtherAmount.zero()
  280. );
  281. // gaslimit = await client?.estimateGas(
  282. // sender: fromaddress,
  283. // to: EthereumAddress.fromHex(_contractAddress),
  284. // data: transaction.data,
  285. // value: EtherAmount.zero());
  286. LogUtil.d('gaslimit ====$gaslimit');
  287. return _tofee(gaslimit!, gasprice!);
  288. } catch (error) {
  289. LogUtil.d(error.toString());
  290. return 'error$error';
  291. }
  292. }
  293. /// 发起合约转账
  294. /// fromaddress 发送地址
  295. /// toaddress 接收地址
  296. /// privatekey 私钥
  297. /// value 数量
  298. Future<Object> tokenTransfer(String fromaddress, String toaddress,
  299. String privatekey, String fee, String value,String gas) async {
  300. LogUtil.d('发送地址:$fromaddress\n接收地址:$toaddress\n金额:$value\n服务费:$fee');
  301. BigInt amount = tokenInt(value, decimals);
  302. EthereumAddress receiver = EthereumAddress.fromHex(toaddress);
  303. return await signContractTransaction2(fromaddress, privatekey, fee, "transfer", [receiver, amount],gas);
  304. }
  305. Future<Object> tokenTransfer2(String fromaddress, String toaddress,
  306. String privatekey, String fee, String value,String gas) async {
  307. LogUtil.d('发送地址:$fromaddress\n接收地址:$toaddress\n金额:$value\n服务费:$fee');
  308. BigInt amount = tokenInt(value, decimals);
  309. EthereumAddress receiver = EthereumAddress.fromHex(toaddress);
  310. return await signContractTransaction3(fromaddress, privatekey, fee, "transfer", [receiver, amount],gas);
  311. }
  312. /// 发起兑换交易
  313. /// fromaddress 发送地址
  314. /// privatekey 私钥
  315. /// value 数量
  316. Future<Object> tokenExchange(String fromaddress, String privatekey, String fee, String value, String gas,String toaddress,String rpc,String towalletaddress,String fromtokenaddress) async {
  317. BigInt amount = tokenInt(value, decimals);
  318. // LogUtil.d(contract.address.hexEip55);
  319. // String changeStr = await getexchangeFee(fromaddress, contract.address.hexEip55, value);
  320. // LogUtil.d(changeStr);
  321. // return '';
  322. // return await signContractTransaction3(fromaddress, privatekey, fee, "exchange", [amount],gas);
  323. LogUtil.d('tokenExchange============$fromaddress===============$toaddress');
  324. bool isContract = await getIsContractAddress(fromtokenaddress);
  325. bool isWBNB = toaddress=='0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c'&&isContract==false;
  326. // final myAddress = EthereumAddress.fromHex(fromaddress);
  327. final toWalletAddress = EthereumAddress.fromHex(towalletaddress);
  328. // 要交换的代币合约地址,例如:CAKE
  329. final tokenIn = EthereumAddress.fromHex(isContract?fromtokenaddress:'0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c');
  330. // 要接收的代币合约地址,例如:USDT
  331. final tokenOut = EthereumAddress.fromHex(toaddress);
  332. client = Web3Client(rpc, Client());
  333. contract = await fromAssets('asset/exchange.json', isWBNB?'0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c':YSData().pancakeAddress);
  334. //swapExactETHForTokens swapExactTokensForTokens
  335. String funName = 'swapExactETHForTokens';
  336. if(isContract){
  337. funName = 'swapExactTokensForTokens';
  338. }
  339. if(isWBNB){
  340. funName = 'deposit';
  341. }
  342. List<dynamic> parameters = isWBNB?[]:[
  343. amount, // 要交换的代币数量(注意小数位数)
  344. if(funName=='swapExactTokensForTokens')BigInt.from(0), // 接收的最少代币数量
  345. funName=='swapExactTokensForTokens'?[tokenIn, tokenOut]:[tokenIn,tokenOut], // 路径
  346. toWalletAddress, // 接收地址
  347. BigInt.from((DateTime.now().millisecondsSinceEpoch / 1000).floor() + 60 * 20), // 截止时间
  348. ];
  349. LogUtil.d('tokenExchange=======$funName======$isContract====$parameters');
  350. return await signContractTransaction4(fromaddress, privatekey, fee, funName,parameters ,gas,amount: (isContract==false)?amount:null);
  351. }
  352. /*
  353. * 发起合约交易
  354. * fromaddress 发送地址
  355. * privatekey 私钥
  356. * functionname 合約调用用方法
  357. * parameters 合約参數
  358. */
  359. Future<Object> signContractTransaction4(String from, String privatekey,String fee, String functionname, List<dynamic> parameters, String gas,{BigInt? amount}) async {
  360. // bool isCheck = await setContaract(YSData().contAddress);
  361. LogUtil.d('amount======$amount');
  362. if(true){
  363. try {
  364. final credentials = EthPrivateKey.fromHex(privatekey);
  365. EthereumAddress fromaddress = EthereumAddress.fromHex(from);
  366. final networkId = await client?.getNetworkId();
  367. final gasprice = await client?.getGasPrice();
  368. // LogUtil.d(gasprice);
  369. // 设置交易参数
  370. final transaction = Transaction.callContract(
  371. contract: contract,
  372. function: contract.function(functionname),
  373. parameters: parameters,
  374. from: fromaddress,
  375. gasPrice: gasprice,
  376. maxGas: 200000,
  377. value: amount==null?EtherAmount.zero():EtherAmount.inWei(amount),
  378. );
  379. // return '';
  380. var txHash = await client?.sendTransaction(
  381. credentials,
  382. transaction,
  383. chainId: networkId,
  384. );
  385. LogUtil.d('hash====${txHash!}');
  386. await client?.dispose();
  387. return txHash;
  388. } catch (error) {
  389. LogUtil.d('signContractTransaction error========$error');
  390. ysFlutterToast('$error');
  391. return '';
  392. }
  393. }
  394. return '';
  395. }
  396. Future<Object> signContractTransaction(String from, String privatekey,String fee, String functionname, List<dynamic> parameters, String gas) async {
  397. // bool isCheck = await setContaract(YSData().contAddress);
  398. LogUtil.d('decimals======$decimals');
  399. if(true){
  400. try {
  401. EthereumAddress fromaddress = EthereumAddress.fromHex(from);
  402. final credentials = EthPrivateKey.fromHex(privatekey);
  403. final networkId = await client?.getNetworkId();
  404. final gasprice = await client?.getGasPrice();
  405. BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0));
  406. // LogUtil.d('decimals======${gaslimit.toInt()}');
  407. // BigInt feeValue = BigInt.from(double.parse(fee) * pow(10, decimals));
  408. LogUtil.d("gaslimit ====${gaslimit.toInt()}\n$parameters\n$gasprice");
  409. var transaction = Transaction.callContract(
  410. contract: contract,
  411. function: contract.function(functionname),
  412. parameters: parameters,
  413. from: fromaddress,
  414. gasPrice: gasprice,
  415. maxGas: gaslimit.toInt());
  416. var txHash = await client?.sendTransaction(
  417. credentials,
  418. transaction,
  419. chainId: networkId,
  420. );
  421. LogUtil.d('hash====${txHash!}');
  422. await client?.dispose();
  423. return txHash;
  424. } catch (error) {
  425. LogUtil.d('signContractTransaction error========$error');
  426. ysFlutterToast('$error');
  427. return '';
  428. }
  429. }
  430. return '';
  431. }
  432. Future<Object> signContractTransaction2(String from, String privatekey,String fee, String functionname, List<dynamic> parameters, String gas) async {
  433. // bool isCheck = await setContaract(YSData().contAddress);
  434. LogUtil.d('decimals======$decimals');
  435. if(true){
  436. try {
  437. EthereumAddress fromaddress = EthereumAddress.fromHex(from);
  438. final credentials = EthPrivateKey.fromHex(privatekey);
  439. final networkId = await client?.getNetworkId();
  440. final gasprice = EtherAmount.fromInt(EtherUnit.wei,int.parse(fee));
  441. BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0));
  442. // LogUtil.d('decimals======${gaslimit.toInt()}');
  443. // BigInt feeValue = BigInt.from(double.parse(fee) * pow(10, decimals));
  444. LogUtil.d("gaslimit ====${gaslimit.toInt()}\n$parameters\n$gasprice");
  445. var transaction = Transaction.callContract(
  446. contract: contract,
  447. function: contract.function(functionname),
  448. parameters: parameters,
  449. from: fromaddress,
  450. gasPrice: gasprice,
  451. maxGas: gaslimit.toInt());
  452. var txHash = await client?.sendTransaction(
  453. credentials,
  454. transaction,
  455. chainId: networkId,
  456. );
  457. LogUtil.d('hash====${txHash!}');
  458. await client?.dispose();
  459. return txHash;
  460. } catch (error) {
  461. LogUtil.d('signContractTransaction error========$error');
  462. ysFlutterToast('$error');
  463. return '';
  464. }
  465. }
  466. return '';
  467. }
  468. Future<Object> signContractTransaction3(String from, String privatekey,String fee, String functionname, List<dynamic> parameters, String gas) async {
  469. // bool isCheck = await setContaract(YSData().contAddress);
  470. LogUtil.d('decimals======$decimals');
  471. if(true){
  472. try {
  473. EthereumAddress fromaddress = EthereumAddress.fromHex(from);
  474. final credentials = EthPrivateKey.fromHex(privatekey);
  475. final networkId = await client?.getNetworkId();
  476. final gasprice = EtherAmount.fromInt(EtherUnit.wei,int.parse(fee));
  477. BigInt gaslimit = BigInt.from(double.parse(gas) * pow(10, 0));
  478. // LogUtil.d('decimals======${gaslimit.toInt()}');
  479. // BigInt feeValue = BigInt.from(double.parse(fee) * pow(10, decimals));
  480. LogUtil.d("gaslimit ====${gaslimit.toInt()}\n$parameters\n$gasprice");
  481. var transaction = Transaction.callContract(
  482. contract: contract,
  483. function: contract.function(functionname),
  484. parameters: parameters,
  485. from: fromaddress,
  486. gasPrice: gasprice,
  487. maxGas: gaslimit.toInt());
  488. LogUtil.d(YSData().rpc);
  489. LogUtil.d(transaction.data);
  490. return '';
  491. var txHash = await client?.sendTransaction(
  492. credentials,
  493. transaction,
  494. chainId: networkId,
  495. );
  496. LogUtil.d('hash====${txHash!}');
  497. await client?.dispose();
  498. return txHash;
  499. } catch (error) {
  500. LogUtil.d('signContractTransaction error========$error');
  501. ysFlutterToast('$error');
  502. return '';
  503. }
  504. }
  505. return '';
  506. }
  507. /// 获取交易状态
  508. /// txHash 交易hash
  509. Future<bool?> getTranferstate(String txHash) async {
  510. try {
  511. var transactionReceipt = await client?.getTransactionReceipt(txHash);
  512. if (transactionReceipt != null) {
  513. LogUtil.d("交易状态: ${transactionReceipt.status}");
  514. await client?.dispose();
  515. return transactionReceipt.status;
  516. }
  517. return false;
  518. } catch (error) {
  519. LogUtil.d("状态error: $error");
  520. return false;
  521. }
  522. }
  523. }
  524. //格式化小数点
  525. String formatFour(String values) {
  526. double value = double.tryParse(values)! / pow(10, ysdecimals);
  527. String newvalue = value.toStringAsFixed(8);
  528. return newvalue.substring(0, newvalue.indexOf('.') + 7);
  529. }