From 057066950ee65027741d48e205ac5d942dd08e61 Mon Sep 17 00:00:00 2001 From: julian Date: Fri, 24 Feb 2023 10:22:25 -0600 Subject: [PATCH] get token transactions refactor --- lib/services/ethereum/ethereum_api.dart | 173 ++++++++++++++++++------ 1 file changed, 130 insertions(+), 43 deletions(-) diff --git a/lib/services/ethereum/ethereum_api.dart b/lib/services/ethereum/ethereum_api.dart index e1ee0784d..926038399 100644 --- a/lib/services/ethereum/ethereum_api.dart +++ b/lib/services/ethereum/ethereum_api.dart @@ -1,16 +1,14 @@ import 'dart:convert'; import 'dart:math'; -import 'package:ethereum_addresses/ethereum_addresses.dart'; import 'package:http/http.dart'; +import 'package:stackwallet/models/ethereum/erc20_token.dart'; import 'package:stackwallet/models/ethereum/erc721_token.dart'; +import 'package:stackwallet/models/ethereum/eth_token.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/utilities/eth_commons.dart'; import 'package:stackwallet/utilities/logger.dart'; -import '../../models/ethereum/erc20_token.dart'; -import '../../models/ethereum/eth_token.dart'; - class AbiRequestResponse { final String message; final String result; @@ -31,6 +29,87 @@ class AbiRequestResponse { } } +class EthTokenTx { + final String blockHash; + final int blockNumber; + final int confirmations; + final String contractAddress; + final int cumulativeGasUsed; + final String from; + final int gas; + final BigInt gasPrice; + final int gasUsed; + final String hash; + final String input; + final int logIndex; + final int nonce; + final int timeStamp; + final String to; + final int tokenDecimal; + final String tokenName; + final String tokenSymbol; + final int transactionIndex; + final BigInt value; + + EthTokenTx({ + required this.blockHash, + required this.blockNumber, + required this.confirmations, + required this.contractAddress, + required this.cumulativeGasUsed, + required this.from, + required this.gas, + required this.gasPrice, + required this.gasUsed, + required this.hash, + required this.input, + required this.logIndex, + required this.nonce, + required this.timeStamp, + required this.to, + required this.tokenDecimal, + required this.tokenName, + required this.tokenSymbol, + required this.transactionIndex, + required this.value, + }); + + factory EthTokenTx.fromMap({ + required Map map, + }) { + try { + return EthTokenTx( + blockHash: map["blockHash"] as String, + blockNumber: int.parse(map["blockNumber"] as String), + confirmations: int.parse(map["confirmations"] as String), + contractAddress: map["contractAddress"] as String, + cumulativeGasUsed: int.parse(map["cumulativeGasUsed"] as String), + from: map["from"] as String, + gas: int.parse(map["gas"] as String), + gasPrice: BigInt.parse(map["gasPrice"] as String), + gasUsed: int.parse(map["gasUsed"] as String), + hash: map["hash"] as String, + input: map["input"] as String, + logIndex: int.parse(map["logIndex"] as String), + nonce: int.parse(map["nonce"] as String), + timeStamp: int.parse(map["timeStamp"] as String), + to: map["to"] as String, + tokenDecimal: int.parse(map["tokenDecimal"] as String), + tokenName: map["tokenName"] as String, + tokenSymbol: map["tokenSymbol"] as String, + transactionIndex: int.parse(map["transactionIndex"] as String), + value: BigInt.parse(map["value"] as String), + ); + } catch (e, s) { + Logging.instance.log( + "EthTokenTx.fromMap() failed: $e\n$s", + level: LogLevel.Fatal, + ); + rethrow; + } + } +} + class EthereumResponse { final T? value; final Exception? exception; @@ -63,6 +142,53 @@ abstract class EthereumAPI { } } + static Future>> getTokenTransactions({ + required String address, + int? startBlock, + int? endBlock, + // todo add more params? + }) async { + try { + final uri = Uri.parse( + "$blockExplorer?module=account&action=tokentx&address=$address", + ); + final response = await get(uri); + + if (response.statusCode == 200) { + final json = jsonDecode(response.body); + if (json["message"] == "OK") { + final result = + List>.from(json["result"] as List); + final List tokenTxns = []; + for (final map in result) { + tokenTxns.add(EthTokenTx.fromMap(map: map)); + } + + return EthereumResponse( + tokenTxns, + null, + ); + } else { + throw Exception(json["message"] as String); + } + } else { + throw Exception( + "getWalletTokens($address) failed with status code: " + "${response.statusCode}", + ); + } + } catch (e, s) { + Logging.instance.log( + "getWalletTokens(): $e\n$s", + level: LogLevel.Error, + ); + return EthereumResponse( + null, + Exception(e.toString()), + ); + } + } + static Future>> getWalletTokens({ required String address, }) async { @@ -129,45 +255,6 @@ abstract class EthereumAPI { } } - static Future> getWalletTokenTransactions( - String address) async { - AddressTransaction tokens = - await fetchAddressTransactions(address, "tokentx"); - List tokensList = []; - var tokenMap = {}; - if (tokens.message == "OK") { - final allTxs = tokens.result; - allTxs.forEach((element) { - print("========================================================="); - print("THING: $element"); - print("========================================================="); - - String key = element["tokenSymbol"] as String; - tokenMap[key] = {}; - tokenMap[key]["balance"] = 0; - - if (tokenMap.containsKey(key)) { - tokenMap[key]["contractAddress"] = - element["contractAddress"] as String; - tokenMap[key]["decimals"] = element["tokenDecimal"]; - tokenMap[key]["name"] = element["tokenName"]; - tokenMap[key]["symbol"] = element["tokenSymbol"]; - if (checksumEthereumAddress(address) == address) { - tokenMap[key]["balance"] += int.parse(element["value"] as String); - } else { - tokenMap[key]["balance"] -= int.parse(element["value"] as String); - } - } - }); - - tokenMap.forEach((key, value) { - tokensList.add(value as Map); - }); - return tokensList; - } - return []; - } - static Future getGasOracle() async { final response = await get(Uri.parse(gasTrackerUrl)); if (response.statusCode == 200) {