diff --git a/lib/services/coins/ethereum/ethereum_wallet.dart b/lib/services/coins/ethereum/ethereum_wallet.dart index d44d5dc5f..b2191da59 100644 --- a/lib/services/coins/ethereum/ethereum_wallet.dart +++ b/lib/services/coins/ethereum/ethereum_wallet.dart @@ -3,11 +3,14 @@ import 'dart:convert'; import 'dart:math'; import 'package:bip39/bip39.dart' as bip39; import 'package:decimal/decimal.dart'; +import 'package:devicelocale/devicelocale.dart'; +import 'package:ethereum_addresses/ethereum_addresses.dart'; import 'package:flutter/foundation.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/models/paymint/utxo_model.dart'; import 'package:stackwallet/services/price.dart'; +import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'; import 'package:stackwallet/utilities/format.dart'; @@ -16,6 +19,7 @@ import 'package:string_to_hex/string_to_hex.dart'; import 'package:web3dart/web3dart.dart'; import 'package:web3dart/web3dart.dart' as web3; import 'package:web3dart/web3dart.dart' as Transaction; +import 'package:stackwallet/models/models.dart' as models; import 'package:http/http.dart'; @@ -142,7 +146,9 @@ class EthereumWallet extends CoinServiceAPI { @override Future get currentReceivingAddress async { final _currentReceivingAddress = _credentials.address; - return _currentReceivingAddress.toString(); + final checkSumAddress = + checksumEthereumAddress(_currentReceivingAddress.toString()); + return checkSumAddress; } @override @@ -360,13 +366,13 @@ class EthereumWallet extends CoinServiceAPI { @override Future refresh() async { print("CALLING REFRESH"); - // if (refreshMutex) { - // Logging.instance.log("$walletId $walletName refreshMutex denied", - // level: LogLevel.Info); - // return; - // } else { - // refreshMutex = true; - // } + if (refreshMutex) { + Logging.instance.log("$walletId $walletName refreshMutex denied", + level: LogLevel.Info); + return; + } else { + refreshMutex = true; + } print("SYNC STATUS IS "); final blockNumber = await _client.getBlockNumber(); @@ -468,15 +474,51 @@ class EthereumWallet extends CoinServiceAPI { } @override - Future updateSentCachedTxData(Map txData) { - // TODO: implement updateSentCachedTxData - throw UnimplementedError(); + Future updateSentCachedTxData(Map txData) async { + final priceData = + await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency); + Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero; + final locale = await Devicelocale.currentLocale; + final String worthNow = Format.localizedStringAsFixed( + value: + ((currentPrice * Decimal.fromInt(txData["recipientAmt"] as int)) / + Decimal.fromInt(Constants.satsPerCoin(coin))) + .toDecimal(scaleOnInfinitePrecision: 2), + decimalPlaces: 2, + locale: locale!); + + final tx = models.Transaction( + txid: txData["txid"] as String, + confirmedStatus: false, + timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000, + txType: "Sent", + amount: txData["recipientAmt"] as int, + worthNow: worthNow, + worthAtBlockTimestamp: worthNow, + fees: txData["fee"] as int, + inputSize: 0, + outputSize: 0, + inputs: [], + outputs: [], + address: txData["address"] as String, + height: -1, + confirmations: 0, + ); + + if (cachedTxData == null) { + final data = await _fetchTransactionData(); + _transactionData = Future(() => data); + } else { + final transactions = cachedTxData!.getAllTransactions(); + transactions[tx.txid] = tx; + cachedTxData = models.TransactionData.fromMap(transactions); + _transactionData = Future(() => cachedTxData!); + } } @override bool validateAddress(String address) { - // TODO: implement validateAddress - return true; + return isValidEthereumAddress(address); } Future _fetchTransactionData() async { @@ -491,123 +533,127 @@ class EthereumWallet extends CoinServiceAPI { print("HEIGHT TO HEX IS $hexHeight"); print('0x$hexHeight'); + final cachedTransactions = + DB.instance.get(boxName: walletId, key: 'latest_tx_model') + as TransactionData?; + final priceData = await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency); Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero; //Initilaize empty transactions array + final List> midSortedArray = []; Map midSortedTx = {}; - for (int i = currentBlock; - i >= 0 && (n > 0 || balance.toDouble() > 0.0); - --i) { - try { - // print(StringToHex.toHexString(i.toString())) - print( - "BLOCK IS $i AND HEX IS --------->>>>>>> ${StringToHex.toHexString(i.toString())}"); - String blockHex = i.toRadixString(16); - var block = await _client.getBlockInformation( - blockNumber: '0x$blockHex', isContainFullObj: true); - - if (block != null && block.transactions != null) { - block.transactions.forEach((element) { - // print("TRANSACTION OBJECT IS $element"); - final jsonObject = json.encode(element); - final decodedTransaction = jsonDecode(jsonObject); - // print(somethingElse['from']); - // print(jsonObject.containsKey(other)); - Logging.instance.log(decodedTransaction, - level: LogLevel.Info, printFullLength: true); - - if (thisAddress == decodedTransaction['from']) { - //Ensure this is not a self send - if (decodedTransaction['from'] != decodedTransaction['to']) { - midSortedTx["txType"] = "Sent"; - midSortedTx["txid"] = decodedTransaction["hash"]; - midSortedTx["height"] = i; - midSortedTx["address"] = decodedTransaction['to']; - int confirmations = 0; - try { - confirmations = currentBlock - i; - } catch (e, s) { - debugPrint("$e $s"); - } - midSortedTx["confirmations"] = confirmations; - midSortedTx["inputSize"] = 1; - midSortedTx["outputSize"] = 1; - midSortedTx["aliens"] = []; - midSortedTx["inputs"] = []; - midSortedTx["outputs"] = []; - - midSortedArray.add(midSortedTx); - Logging.instance.log( - "TX SENT FROM THIS ACCOUNT ${decodedTransaction['from']} ${decodedTransaction['to']}", - level: LogLevel.Info); - --n; - } - - if (thisAddress == decodedTransaction['to']) { - if (decodedTransaction['from'] != decodedTransaction['to']) { - midSortedTx["txType"] = "Received"; - midSortedTx["txid"] = decodedTransaction["hash"]; - midSortedTx["height"] = i; - midSortedTx["address"] = decodedTransaction['from']; - int confirmations = 0; - try { - confirmations = currentBlock - i; - } catch (e, s) { - debugPrint("$e $s"); - } - midSortedTx["confirmations"] = confirmations; - midSortedTx["inputSize"] = 1; - midSortedTx["outputSize"] = 1; - midSortedTx["aliens"] = []; - midSortedTx["inputs"] = []; - midSortedTx["outputs"] = []; - midSortedArray.add(midSortedTx); - } - } - } - }); - } - } catch (e, s) { - print("Error getting transactions ${e.toString()} $s"); - } - } - - midSortedArray - .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int)); - final Map result = {"dateTimeChunks": []}; - final dateArray = []; - - for (int i = 0; i < midSortedArray.length; i++) { - final txObject = midSortedArray[i]; - final date = extractDateFromTimestamp(txObject["timestamp"] as int); - final txTimeArray = [txObject["timestamp"], date]; - - if (dateArray.contains(txTimeArray[1])) { - result["dateTimeChunks"].forEach((dynamic chunk) { - if (extractDateFromTimestamp(chunk["timestamp"] as int) == - txTimeArray[1]) { - if (chunk["transactions"] == null) { - chunk["transactions"] = >[]; - } - chunk["transactions"].add(txObject); - } - }); - } else { - dateArray.add(txTimeArray[1]); - final chunk = { - "timestamp": txTimeArray[0], - "transactions": [txObject], - }; - result["dateTimeChunks"].add(chunk); - } - } - - final transactionsMap = cachedTransactions?.getAllTransactions() ?? {}; - transactionsMap - .addAll(TransactionData.fromJson(result).getAllTransactions()); + // for (int i = currentBlock; + // i >= 0 && (n > 0 || balance.toDouble() > 0.0); + // --i) { + // try { + // // print(StringToHex.toHexString(i.toString())) + // print( + // "BLOCK IS $i AND HEX IS --------->>>>>>> ${StringToHex.toHexString(i.toString())}"); + // String blockHex = i.toRadixString(16); + // var block = await _client.getBlockInformation( + // blockNumber: '0x$blockHex', isContainFullObj: true); + // + // if (block != null && block.transactions != null) { + // block.transactions.forEach((element) { + // // print("TRANSACTION OBJECT IS $element"); + // final jsonObject = json.encode(element); + // final decodedTransaction = jsonDecode(jsonObject); + // // print(somethingElse['from']); + // // print(jsonObject.containsKey(other)); + // Logging.instance.log(decodedTransaction, + // level: LogLevel.Info, printFullLength: true); + // + // if (thisAddress == decodedTransaction['from']) { + // //Ensure this is not a self send + // if (decodedTransaction['from'] != decodedTransaction['to']) { + // midSortedTx["txType"] = "Sent"; + // midSortedTx["txid"] = decodedTransaction["hash"]; + // midSortedTx["height"] = i; + // midSortedTx["address"] = decodedTransaction['to']; + // int confirmations = 0; + // try { + // confirmations = currentBlock - i; + // } catch (e, s) { + // debugPrint("$e $s"); + // } + // midSortedTx["confirmations"] = confirmations; + // midSortedTx["inputSize"] = 1; + // midSortedTx["outputSize"] = 1; + // midSortedTx["aliens"] = []; + // midSortedTx["inputs"] = []; + // midSortedTx["outputs"] = []; + // + // midSortedArray.add(midSortedTx); + // Logging.instance.log( + // "TX SENT FROM THIS ACCOUNT ${decodedTransaction['from']} ${decodedTransaction['to']}", + // level: LogLevel.Info); + // --n; + // } + // + // if (thisAddress == decodedTransaction['to']) { + // if (decodedTransaction['from'] != decodedTransaction['to']) { + // midSortedTx["txType"] = "Received"; + // midSortedTx["txid"] = decodedTransaction["hash"]; + // midSortedTx["height"] = i; + // midSortedTx["address"] = decodedTransaction['from']; + // int confirmations = 0; + // try { + // confirmations = currentBlock - i; + // } catch (e, s) { + // debugPrint("$e $s"); + // } + // midSortedTx["confirmations"] = confirmations; + // midSortedTx["inputSize"] = 1; + // midSortedTx["outputSize"] = 1; + // midSortedTx["aliens"] = []; + // midSortedTx["inputs"] = []; + // midSortedTx["outputs"] = []; + // midSortedArray.add(midSortedTx); + // } + // } + // } + // }); + // } + // } catch (e, s) { + // print("Error getting transactions ${e.toString()} $s"); + // } + // } + // midSortedArray + // .sort((a, b) => (b["timestamp"] as int) - (a["timestamp"] as int)); + // final Map result = {"dateTimeChunks": []}; + // final dateArray = []; + // + // for (int i = 0; i < midSortedArray.length; i++) { + // final txObject = midSortedArray[i]; + // final date = extractDateFromTimestamp(txObject["timestamp"] as int); + // final txTimeArray = [txObject["timestamp"], date]; + // + // if (dateArray.contains(txTimeArray[1])) { + // result["dateTimeChunks"].forEach((dynamic chunk) { + // if (extractDateFromTimestamp(chunk["timestamp"] as int) == + // txTimeArray[1]) { + // if (chunk["transactions"] == null) { + // chunk["transactions"] = >[]; + // } + // chunk["transactions"].add(txObject); + // } + // }); + // } else { + // dateArray.add(txTimeArray[1]); + // final chunk = { + // "timestamp": txTimeArray[0], + // "transactions": [txObject], + // }; + // result["dateTimeChunks"].add(chunk); + // } + // } + // + // final transactionsMap = cachedTransactions?.getAllTransactions() ?? {}; + // transactionsMap + // .addAll(TransactionData.fromJson(result).getAllTransactions()); print("THIS CURRECT ADDRESS IS $thisAddress"); print("THIS CURRECT BLOCK IS $currentBlock"); diff --git a/pubspec.lock b/pubspec.lock index 81a63d518..e15d53505 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -225,7 +225,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.3.0" + version: "4.4.0" collection: dependency: transitive description: @@ -429,6 +429,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.0.1" + ethereum_addresses: + dependency: "direct main" + description: + name: ethereum_addresses + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" event_bus: dependency: "direct main" description: @@ -1284,7 +1291,7 @@ packages: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" shared_preferences_macos: dependency: transitive description: @@ -1312,7 +1319,7 @@ packages: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" shelf: dependency: transitive description: @@ -1683,7 +1690,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "3.1.2" + version: "3.1.3" window_size: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 25119a355..1da77f560 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,6 +91,7 @@ dependencies: # Eth Plugins web3dart: 2.3.5 string_to_hex: 0.2.2 + ethereum_addresses: 1.0.2 # Storage plugins flutter_secure_storage: ^5.0.2