From 652da68e257da55f681d21297023e473a353f35d Mon Sep 17 00:00:00 2001 From: Likho Date: Tue, 30 Aug 2022 07:26:45 -0500 Subject: [PATCH 1/7] Open wallet once and store instrance --- crypto_plugins/flutter_libepiccash | 2 +- .../coins/epiccash/epiccash_wallet.dart | 315 ++++++++---------- 2 files changed, 140 insertions(+), 177 deletions(-) diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index b9423d604..a1826673d 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit b9423d604eca52f3ea3c3f1ded52c0ad07248837 +Subproject commit a1826673d6643c8ec24ad96ce538434a60c6e4fb diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index c0cb9e4e9..d46512bfb 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -7,6 +7,7 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:hive/hive.dart'; import 'package:http/http.dart'; import 'package:mutex/mutex.dart'; import 'package:path_provider/path_provider.dart'; @@ -61,123 +62,110 @@ Future executeNative(Map arguments) async { final function = arguments['function'] as String; try { if (function == "scanOutPuts") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final startHeight = arguments['startHeight'] as int?; final numberOfBlocks = arguments['numberOfBlocks'] as int?; Map result = {}; - if (!(config == null || - password == null || + if (!(wallet == null || startHeight == null || numberOfBlocks == null)) { var outputs = - await scanOutPuts(config, password, startHeight, numberOfBlocks); + await scanOutPuts(wallet, startHeight, numberOfBlocks); result['outputs'] = outputs; sendPort.send(result); return; } } else if (function == "getPendingSlates") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final secretKeyIndex = arguments['secretKeyIndex'] as int?; final slates = arguments['slates'] as String; Map result = {}; - if (!(config == null || password == null || secretKeyIndex == null)) { + if (!(wallet == null || secretKeyIndex == null)) { Logging.instance .log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info); result['result'] = - await getPendingSlates(config, password, secretKeyIndex, slates); + await getPendingSlates(wallet, secretKeyIndex, slates); sendPort.send(result); return; } } else if (function == "subscribeRequest") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final secretKeyIndex = arguments['secretKeyIndex'] as int?; final epicboxConfig = arguments['epicboxConfig'] as String?; Map result = {}; - if (!(config == null || - password == null || + if (!(wallet == null || secretKeyIndex == null || epicboxConfig == null)) { Logging.instance .log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info); result['result'] = await getSubscribeRequest( - config, password, secretKeyIndex, epicboxConfig); + wallet, secretKeyIndex, epicboxConfig); sendPort.send(result); return; } } else if (function == "processSlates") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final slates = arguments['slates']; Map result = {}; - if (!(config == null || password == null || slates == null)) { + if (!(wallet == null || slates == null)) { result['result'] = - await processSlates(config, password, slates.toString()); + await processSlates(wallet, slates.toString()); sendPort.send(result); return; } } else if (function == "getWalletInfo") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final refreshFromNode = arguments['refreshFromNode'] as int?; final minimumConfirmations = arguments['minimumConfirmations'] as int?; Map result = {}; - if (!(config == null || - password == null || + if (!(wallet == null || refreshFromNode == null || minimumConfirmations == null)) { var res = await getWalletInfo( - config, password, refreshFromNode, minimumConfirmations); + wallet, refreshFromNode, minimumConfirmations); result['result'] = res; sendPort.send(result); return; } } else if (function == "getTransactions") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final refreshFromNode = arguments['refreshFromNode'] as int?; Map result = {}; - if (!(config == null || password == null || refreshFromNode == null)) { - var res = await getTransactions(config, password, refreshFromNode); + if (!(wallet == null || refreshFromNode == null)) { + var res = await getTransactions(wallet, refreshFromNode); result['result'] = res; sendPort.send(result); return; } } else if (function == "startSync") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; const int refreshFromNode = 1; Map result = {}; - if (!(config == null || password == null)) { - var res = await getWalletInfo(config, password, refreshFromNode, 10); + if (!(wallet == null)) { + var res = await getWalletInfo(wallet, refreshFromNode, 10); result['result'] = res; sendPort.send(result); return; } } else if (function == "getTransactionFees") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final amount = arguments['amount'] as int?; final minimumConfirmations = arguments['minimumConfirmations'] as int?; Map result = {}; - if (!(config == null || - password == null || + if (!(wallet == null || amount == null || minimumConfirmations == null)) { var res = await getTransactionFees( - config, password, amount, minimumConfirmations); + wallet, amount, minimumConfirmations); result['result'] = res; sendPort.send(result); return; } } else if (function == "createTransaction") { - final config = arguments['config'] as String?; - final password = arguments['password'] as String?; + final wallet = arguments['wallet'] as String?; final amount = arguments['amount'] as int?; final address = arguments['address'] as String?; final secretKeyIndex = arguments['secretKeyIndex'] as int?; @@ -185,14 +173,13 @@ Future executeNative(Map arguments) async { final minimumConfirmations = arguments['minimumConfirmations'] as int?; Map result = {}; - if (!(config == null || - password == null || + if (!(wallet == null || amount == null || address == null || secretKeyIndex == null || epicboxConfig == null || minimumConfirmations == null)) { - var res = await createTransaction(config, password, amount, address, + var res = await createTransaction(wallet, amount, address, secretKeyIndex, epicboxConfig, minimumConfirmations); result['result'] = res; sendPort.send(result); @@ -225,14 +212,14 @@ void stop(ReceivePort port) { // Keep Wrapper functions outside of the class to avoid memory leaks and errors about receive ports and illegal arguments. // TODO: Can get rid of this wrapper and call it in a full isolate instead of compute() if we want more control over this Future _cancelTransactionWrapper( - Tuple3 data) async { + Tuple2 data) async { // assuming this returns an empty string on success // or an error message string on failure - return cancelTransaction(data.item1, data.item2, data.item3); + return cancelTransaction(data.item1, data.item2); } -Future _deleteWalletWrapper(Tuple2 data) async { - return deleteWallet(data.item1, data.item2); +Future _deleteWalletWrapper(String wallet) async { + return deleteWallet(wallet); } Future deleteEpicWallet({ @@ -255,9 +242,9 @@ Future deleteEpicWallet({ config = jsonEncode(editConfig); } - final password = await secureStore.read(key: '${walletId}_password'); + final wallet = await secureStore.read(key: '${walletId}_wallet'); - return compute(_deleteWalletWrapper, Tuple2(config!, password!)); + return compute(_deleteWalletWrapper, wallet!); } Future _initWalletWrapper( @@ -268,9 +255,9 @@ Future _initWalletWrapper( } Future _initGetAddressInfoWrapper( - Tuple4 data) async { + Tuple3 data) async { String walletAddress = - getAddressInfo(data.item1, data.item2, data.item3, data.item4); + getAddressInfo(data.item1, data.item2, data.item3); return walletAddress; } @@ -564,16 +551,14 @@ class EpicCashWallet extends CoinServiceAPI { Future startSync() async { Logging.instance.log("request start sync", level: LogLevel.Info); - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); if (!syncMutex.isLocked) { await syncMutex.protect(() async { Logging.instance.log("sync started", level: LogLevel.Info); ReceivePort receivePort = await getIsolate({ "function": "startSync", - "config": config, - "password": password!, + "wallet": wallet!, }, name: walletName); this.receivePort = receivePort; @@ -596,17 +581,14 @@ class EpicCashWallet extends CoinServiceAPI { } Future allWalletBalances() async { - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); - + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 0; dynamic message; await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "getWalletInfo", - "config": config, - "password": password!, + "wallet": wallet!, "refreshFromNode": refreshFromNode, "minimumConfirmations": MINIMUM_CONFIRMATIONS, }, name: walletName); @@ -652,9 +634,7 @@ class EpicCashWallet extends CoinServiceAPI { late PriceAPI _priceAPI; Future cancelPendingTransactionAndPost(String tx_slate_id) async { - final String config = await getRealConfig(); - final String password = - (await _secureStore.read(key: '${_walletId}_password'))!; + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); final int? receivingIndex = DB.instance .get(boxName: walletId, key: "receivingIndex") as int?; final epicboxConfig = @@ -677,8 +657,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "subscribeRequest", - "config": config, - "password": password, + "wallet": wallet, "secretKeyIndex": currentReceivingIndex!, "epicboxConfig": epicboxConfig, }, name: walletName); @@ -713,17 +692,15 @@ class EpicCashWallet extends CoinServiceAPI { // /// returns an empty String on success, error message on failure Future cancelPendingTransaction(String tx_slate_id) async { - final String config = await getRealConfig(); - final String password = - (await _secureStore.read(key: '${_walletId}_password'))!; + final String wallet = + (await _secureStore.read(key: '${_walletId}_wallet'))!; String? result; await m.protect(() async { result = await compute( _cancelTransactionWrapper, - Tuple3( - config, - password, + Tuple2( + wallet, tx_slate_id, ), ); @@ -734,8 +711,7 @@ class EpicCashWallet extends CoinServiceAPI { @override Future confirmSend({required Map txData}) async { try { - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); final epicboxConfig = await _secureStore.read(key: '${_walletId}_epicboxConfig'); @@ -744,8 +720,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "createTransaction", - "config": config, - "password": password!, + "wallet": wallet!, "amount": txData['recipientAmt'], "address": txData['addresss'], "secretKeyIndex": 0, @@ -782,17 +757,18 @@ class EpicCashWallet extends CoinServiceAPI { txData['addresss'] as String, postSlateRequest as String); Logging.instance .log("POST_SLATE_IS $postToServer", level: LogLevel.Info); - //await postSlate final txCreateResult = decodeData[0]; // //TODO: second problem - final transaction = txCreateResult[0]; - - // final wallet = await Hive.openBox(_walletId); - // final slateToAddresses = (await wallet.get("slate_to_address")) as Map?; - // slateToAddresses![transaction[0]['tx_slate_id']] = txData['addresss']; - // await wallet.put('slate_to_address', slateToAddresses); - // return transaction[0]['tx_slate_id'] as String; - return ""; + final transaction = json.decode(txCreateResult as String); + final tx = transaction[0]; + final txLogEntry = json.decode(tx as String); + final txLogEntryFirst = txLogEntry[0]; + Logger.print("TX_LOG_ENTRY_IS $txLogEntryFirst"); + final wallet = await Hive.openBox(_walletId); + final slateToAddresses = (await wallet.get("slate_to_address")) as Map?; + slateToAddresses?[txLogEntryFirst['tx_slate_id']] = txData['addresss']; + await wallet.put('slate_to_address', slateToAddresses); + return txLogEntryFirst['tx_slate_id'] as String; } } catch (e, s) { Logging.instance.log("Error sending $e - $s", level: LogLevel.Error); @@ -806,8 +782,7 @@ class EpicCashWallet extends CoinServiceAPI { Future _getCurrentAddressForChain( int chain, ) async { - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); final epicboxConfig = await _secureStore.read(key: '${_walletId}_epicboxConfig'); @@ -815,7 +790,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { walletAddress = await compute( _initGetAddressInfoWrapper, - Tuple4(config, password!, chain, epicboxConfig!), + Tuple3(wallet!, chain, epicboxConfig!), ); }); Logging.instance @@ -920,6 +895,13 @@ class EpicCashWallet extends CoinServiceAPI { Logging.instance.log("Opening existing ${coin.prettyName} wallet", level: LogLevel.Info); + final config = await getRealConfig(); + final password = + await _secureStore.read(key: '${_walletId}_password'); + + final walletOpen = openWallet(config!, password!); + await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen); + if ((DB.instance.get(boxName: walletId, key: "id")) == null) { debugPrint("Exception was thrown"); throw Exception( @@ -937,8 +919,7 @@ class EpicCashWallet extends CoinServiceAPI { } Future storeEpicboxInfo() async { - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); int index = 0; Logging.instance.log("This index is $index", level: LogLevel.Info); @@ -948,7 +929,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { walletAddress = await compute( _initGetAddressInfoWrapper, - Tuple4(config, password!, index, epicboxConfig!), + Tuple3(wallet!, index, epicboxConfig!), ); }); Logging.instance @@ -1008,6 +989,10 @@ class EpicCashWallet extends CoinServiceAPI { ); }); + //Open wallet + final walletOpen = openWallet(stringConfig, password); + await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen); + //Store Epic box address info await storeEpicboxInfo(); @@ -1106,16 +1091,14 @@ class EpicCashWallet extends CoinServiceAPI { Future nativeFee(int satoshiAmount, {bool ifErrorEstimateFee = false}) async { - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); try { String? transactionFees; await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "getTransactionFees", - "config": config, - "password": password!, + "wallet": wallet!, "amount": satoshiAmount, "minimumConfirmations": MINIMUM_CONFIRMATIONS, }, name: walletName); @@ -1241,8 +1224,8 @@ class EpicCashWallet extends CoinServiceAPI { Future startScans() async { try { - String stringConfig = await getConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); var restoreHeight = DB.instance.get(boxName: walletId, key: "restoreHeight"); @@ -1272,8 +1255,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "scanOutPuts", - "config": stringConfig, - "password": password, + "wallet": wallet!, "startHeight": lastScannedBlock, "numberOfBlocks": MAX_PER_LOOP, }, name: walletName); @@ -1356,9 +1338,6 @@ class EpicCashWallet extends CoinServiceAPI { ), ); - //Store Epic box address info - await storeEpicboxInfo(); - await DB.instance .put(boxName: walletId, key: "restoreHeight", value: height); @@ -1387,27 +1366,13 @@ class EpicCashWallet extends CoinServiceAPI { await DB.instance .put(boxName: walletId, key: "isFavorite", value: false); - //Scan wallet - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "scanOutPuts", - "config": stringConfig, - "password": password, - "startHeight": 1550000, - "numberOfBlocks": 100, - }, name: walletName); + //Open Wallet + final walletOpen = openWallet(stringConfig, password); + await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen); + + //Store Epic box address info + await storeEpicboxInfo(); - var message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("scanOutPuts isolate failed"); - } - stop(receivePort); - Logging.instance - .log('Closing scanOutPuts!\n $message', level: LogLevel.Info); - }); } catch (e, s) { Logging.instance .log("Error recovering wallet $e\n$s", level: LogLevel.Error); @@ -1588,16 +1553,14 @@ class EpicCashWallet extends CoinServiceAPI { currentReceivingIndex++) { final currentAddress = await _getCurrentAddressForChain(currentReceivingIndex); - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); final epicboxConfig = await _secureStore.read(key: '${_walletId}_epicboxConfig'); dynamic subscribeRequest; await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "subscribeRequest", - "config": config, - "password": password, + "wallet": wallet, "secretKeyIndex": currentReceivingIndex, "epicboxConfig": epicboxConfig, }, name: walletName); @@ -1636,8 +1599,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "getPendingSlates", - "config": config, - "password": password, + "wallet": wallet!, "secretKeyIndex": currentReceivingIndex, "slates": encoded, }, name: walletName); @@ -1668,8 +1630,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "processSlates", - "config": config, - "password": password, + "wallet": wallet!, "slates": slateMessage }, name: walletName); @@ -1689,51 +1650,57 @@ class EpicCashWallet extends CoinServiceAPI { await deleteSlate(currentAddress, subscribeRequest['signature'] as String, slate as String); } - var decodedResponse = json.decode(response); - Logging.instance.log("PROCESS_SLATE_RESPONSE $response", + + Logging.instance.log("RESPONSE_FOR_PROCESS_IS $response", + level: LogLevel.Info); + Logging.instance.log("PROCESS_SLATE_RESPONSE $response", level: LogLevel.Info); - final processStatus = json.decode(decodedResponse[0] as String); - String slateStatus = processStatus['status'] as String; - // Logging.instance.log("THIS_TEXT $processStatus"); - if (slateStatus == "PendingProcessing") { - //Encrypt slate - // - String encryptedSlate = await getEncryptedSlate( - config, - password!, - slateSender, - currentReceivingIndex, - epicboxConfig!, - decodedResponse[1] as String); - - final postSlateToServer = - await postSlate(slateSender, encryptedSlate); - - await deleteSlate(currentAddress, - subscribeRequest['signature'] as String, slate as String); - Logging.instance.log("POST_SLATE_RESPONSE $postSlateToServer", + if (response.contains("Error Wallet store error: DB Not Found Error")) { + //Already processed - to be deleted + //TODO - DELETE ALREADY PROCESSED SLATE + Logging.instance.log("SLATE ALREADY PROCESSED - NEEDS TO BE DELETED $response", level: LogLevel.Info); } else { - //Finalise Slate - final processSlate = json.decode(decodedResponse[1] as String); - Logging.instance.log( - "PROCESSED_SLATE_TO_FINALIZE $processSlate", - level: LogLevel.Info); - final tx = json.decode(processSlate[0] as String); - Logging.instance.log("TX_IS $tx", level: LogLevel.Info); - String txSlateId = tx[0]['tx_slate_id'] as String; - Logging.instance - .log("TX_SLATE_ID_IS $txSlateId", level: LogLevel.Info); -// - final postToNode = await postSlateToNode( - config, password!, currentReceivingIndex, txSlateId); - await deleteSlate(currentAddress, - subscribeRequest['signature'] as String, slate as String); - Logging.instance.log("POST_SLATE_RESPONSE $postToNode", - level: LogLevel.Info); - //Post Slate to Node - Logging.instance.log("Finalise slate", level: LogLevel.Info); + var decodedResponse = json.decode(response); + final processStatus = json.decode(decodedResponse[0] as String); + String slateStatus = processStatus['status'] as String; + if (slateStatus == "PendingProcessing") { + //Encrypt slate + String encryptedSlate = await getEncryptedSlate( + wallet!, + slateSender, + currentReceivingIndex, + epicboxConfig!, + decodedResponse[1] as String); + + final postSlateToServer = + await postSlate(slateSender, encryptedSlate); + + await deleteSlate(currentAddress, + subscribeRequest['signature'] as String, slate as String); + Logging.instance.log("POST_SLATE_RESPONSE $postSlateToServer", + level: LogLevel.Info); + } else { + //Finalise Slate + final processSlate = json.decode(decodedResponse[1] as String); + Logging.instance.log( + "PROCESSED_SLATE_TO_FINALIZE $processSlate", + level: LogLevel.Info); + final tx = json.decode(processSlate[0] as String); + Logging.instance.log("TX_IS $tx", level: LogLevel.Info); + String txSlateId = tx[0]['tx_slate_id'] as String; + Logging.instance + .log("TX_SLATE_ID_IS $txSlateId", level: LogLevel.Info); + final postToNode = await postSlateToNode( + wallet!, txSlateId); + await deleteSlate(currentAddress, + subscribeRequest['signature'] as String, slate as String); + Logging.instance.log("POST_SLATE_RESPONSE $postToNode", + level: LogLevel.Info); + //Post Slate to Node + Logging.instance.log("Finalise slate", level: LogLevel.Info); + } } } catch (e, s) { Logging.instance.log("$e\n$s", level: LogLevel.Info); @@ -1751,8 +1718,7 @@ class EpicCashWallet extends CoinServiceAPI { Future processAllCancels() async { Logging.instance.log("processAllCancels", level: LogLevel.Info); - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); final epicboxConfig = await _secureStore.read(key: '${_walletId}_epicboxConfig'); final int? receivingIndex = DB.instance @@ -1768,8 +1734,7 @@ class EpicCashWallet extends CoinServiceAPI { await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "subscribeRequest", - "config": config, - "password": password, + "wallet": wallet!, "secretKeyIndex": currentReceivingIndex, "epicboxConfig": epicboxConfig, }, name: walletName); @@ -2036,16 +2001,14 @@ class EpicCashWallet extends CoinServiceAPI { Future _fetchTransactionData() async { final currentChainHeight = await chainHeight; - final config = await getRealConfig(); - final password = await _secureStore.read(key: '${_walletId}_password'); + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 0; dynamic message; await m.protect(() async { ReceivePort receivePort = await getIsolate({ "function": "getTransactions", - "config": config, - "password": password!, + "wallet": wallet!, "refreshFromNode": refreshFromNode, }, name: walletName); From 345889c56632fdf55d818ff7aba5be9f2864749e Mon Sep 17 00:00:00 2001 From: Likho Date: Tue, 30 Aug 2022 07:57:48 -0500 Subject: [PATCH 2/7] Delete already processed slate --- lib/services/coins/epiccash/epiccash_wallet.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index d46512bfb..40d179312 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1659,7 +1659,10 @@ class EpicCashWallet extends CoinServiceAPI { if (response.contains("Error Wallet store error: DB Not Found Error")) { //Already processed - to be deleted //TODO - DELETE ALREADY PROCESSED SLATE - Logging.instance.log("SLATE ALREADY PROCESSED - NEEDS TO BE DELETED $response", + Logging.instance.log("DELETING_PROCESSED_SLATE", + level: LogLevel.Info); + final slateDelete = await deleteSlate(currentAddress, subscribeRequest['signature'] as String, slate as String); + Logging.instance.log("DELETE_SLATE_RESPONSE $slateDelete", level: LogLevel.Info); } else { var decodedResponse = json.decode(response); From 0eaf4eb5e272b265bf06791b7238225c2e2c3e3f Mon Sep 17 00:00:00 2001 From: Likho Date: Tue, 30 Aug 2022 08:00:23 -0500 Subject: [PATCH 3/7] Clean up logs --- lib/services/coins/epiccash/epiccash_wallet.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 40d179312..07ef32ded 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1651,14 +1651,8 @@ class EpicCashWallet extends CoinServiceAPI { subscribeRequest['signature'] as String, slate as String); } - Logging.instance.log("RESPONSE_FOR_PROCESS_IS $response", - level: LogLevel.Info); - Logging.instance.log("PROCESS_SLATE_RESPONSE $response", - level: LogLevel.Info); - if (response.contains("Error Wallet store error: DB Not Found Error")) { //Already processed - to be deleted - //TODO - DELETE ALREADY PROCESSED SLATE Logging.instance.log("DELETING_PROCESSED_SLATE", level: LogLevel.Info); final slateDelete = await deleteSlate(currentAddress, subscribeRequest['signature'] as String, slate as String); From d49fc8881af3604b59004320a2bd3156c03a4958 Mon Sep 17 00:00:00 2001 From: Likho Date: Tue, 30 Aug 2022 09:44:36 -0500 Subject: [PATCH 4/7] Update IOS header file signatures --- crypto_plugins/flutter_libepiccash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index a1826673d..8e4274f81 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit a1826673d6643c8ec24ad96ce538434a60c6e4fb +Subproject commit 8e4274f817dd3875e105e026aaecf6a33415a8c7 From bf186fe2bbf1232b6ee236f0218fbf1ddd4ae635 Mon Sep 17 00:00:00 2001 From: Likho Date: Thu, 1 Sep 2022 04:24:59 -0500 Subject: [PATCH 5/7] Add HTTP send method for epiccash --- crypto_plugins/flutter_libepiccash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index 8e4274f81..5ae20e71c 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit 8e4274f817dd3875e105e026aaecf6a33415a8c7 +Subproject commit 5ae20e71c0bb85952866fdd6aa7572438517943e From cfcd7a7928cc6275fdf25501866ce82e5ccdb998 Mon Sep 17 00:00:00 2001 From: Likho Date: Thu, 1 Sep 2022 16:17:46 -0500 Subject: [PATCH 6/7] Implement HTTP sending and use Julian's error checking --- .../send_view/confirm_transaction_view.dart | 77 +++++++---- .../coins/epiccash/epiccash_wallet.dart | 128 ++++++++++++++---- 2 files changed, 152 insertions(+), 53 deletions(-) diff --git a/lib/pages/send_view/confirm_transaction_view.dart b/lib/pages/send_view/confirm_transaction_view.dart index 82422ab3c..4494790cc 100644 --- a/lib/pages/send_view/confirm_transaction_view.dart +++ b/lib/pages/send_view/confirm_transaction_view.dart @@ -1,12 +1,17 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart'; import 'package:stackwallet/pages/wallet_view/wallet_view.dart'; import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/route_generator.dart'; +import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart'; import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; +import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; @@ -40,25 +45,25 @@ class _ConfirmTransactionViewState late final String routeOnSuccessName; Future _attemptSend(BuildContext context) async { - showDialog( + unawaited(showDialog( context: context, useSafeArea: false, barrierDismissible: false, builder: (context) { return const SendingTransactionDialog(); }, - ); + )); final note = transactionInfo["note"] as String? ?? ""; final manager = - ref.read(walletsChangeNotifierProvider).getManager(walletId); + ref.read(walletsChangeNotifierProvider).getManager(walletId); try { final txid = await manager.confirmSend(txData: transactionInfo); - manager.refresh(); + unawaited(manager.refresh()); // save note - ref + await ref .read(notesServiceChangeNotifierProvider(walletId)) .editOrAddNote(txid: txid, note: note); @@ -66,12 +71,26 @@ class _ConfirmTransactionViewState if (mounted) { Navigator.of(context).popUntil(ModalRoute.withName(routeOnSuccessName)); } + } on BadEpicHttpAddressException catch (_) { + if (mounted) { + // pop building dialog + Navigator.of(context).pop(); + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: + "Connection failed. Please check the address and try again.", + context: context, + ), + ); + return; + } } catch (e, s) { debugPrint("$e\n$s"); // pop sending dialog Navigator.of(context).pop(); - showDialog( + await showDialog( context: context, useSafeArea: false, barrierDismissible: true, @@ -81,10 +100,10 @@ class _ConfirmTransactionViewState message: e.toString(), rightButton: TextButton( style: Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: MaterialStateProperty.all( - CFColors.buttonGray, - ), - ), + backgroundColor: MaterialStateProperty.all( + CFColors.buttonGray, + ), + ), child: Text( "Ok", style: STextStyles.button.copyWith( @@ -193,9 +212,9 @@ class _ConfirmTransactionViewState .select((value) => value.locale), ), )} ${ref.watch( - managerProvider - .select((value) => value.coin), - ).ticker}", + managerProvider + .select((value) => value.coin), + ).ticker}", style: STextStyles.itemSubtitle12, textAlign: TextAlign.right, ), @@ -221,9 +240,9 @@ class _ConfirmTransactionViewState .select((value) => value.locale), ), )} ${ref.watch( - managerProvider - .select((value) => value.coin), - ).ticker}", + managerProvider + .select((value) => value.coin), + ).ticker}", style: STextStyles.itemSubtitle12, textAlign: TextAlign.right, ), @@ -273,9 +292,9 @@ class _ConfirmTransactionViewState .select((value) => value.locale), ), )} ${ref.watch( - managerProvider - .select((value) => value.coin), - ).ticker}", + managerProvider + .select((value) => value.coin), + ).ticker}", style: STextStyles.itemSubtitle12, textAlign: TextAlign.right, ), @@ -287,18 +306,18 @@ class _ConfirmTransactionViewState ), TextButton( style: - Theme.of(context).textButtonTheme.style?.copyWith( - backgroundColor: - MaterialStateProperty.all( - CFColors.stackAccent, - ), - ), + Theme.of(context).textButtonTheme.style?.copyWith( + backgroundColor: + MaterialStateProperty.all( + CFColors.stackAccent, + ), + ), onPressed: () async { final unlocked = await Navigator.push( context, RouteGenerator.getRoute( shouldUseMaterialRoute: - RouteGenerator.useMaterialPageRoute, + RouteGenerator.useMaterialPageRoute, builder: (_) => const LockscreenView( showBackButton: true, popOnSuccess: true, @@ -306,9 +325,9 @@ class _ConfirmTransactionViewState routeOnSuccess: "", biometricsCancelButtonString: "CANCEL", biometricsLocalizedReason: - "Authenticate to send transaction", + "Authenticate to send transaction", biometricsAuthenticationTitle: - "Confirm Transaction", + "Confirm Transaction", ), settings: const RouteSettings( name: "/confirmsendlockscreen"), @@ -316,7 +335,7 @@ class _ConfirmTransactionViewState ); if (unlocked is bool && unlocked && mounted) { - _attemptSend(context); + unawaited(_attemptSend(context)); } }, child: Text( diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 4c3f7863d..53a320666 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -40,6 +40,17 @@ const int MINIMUM_CONFIRMATIONS = 10; const String GENESIS_HASH_MAINNET = ""; const String GENESIS_HASH_TESTNET = ""; +class BadEpicHttpAddressException implements Exception { + final String? message; + + BadEpicHttpAddressException({this.message}); + + @override + String toString() { + return "BadEpicHttpAddressException: $message"; + } +} + // isolate Map isolates = {}; @@ -185,6 +196,29 @@ Future executeNative(Map arguments) async { sendPort.send(result); return; } + } else if (function == "txHttpSend") { + final wallet = arguments['wallet'] as String?; + final selectionStrategyIsAll = arguments['selectionStrategyIsAll'] as int?; + final minimumConfirmations = arguments['minimumConfirmations'] as int?; + final message = arguments['message'] as String?; + final amount = arguments['amount'] as int?; + final address = arguments['address'] as String?; + + Map result = {}; + + if (!(wallet == null || + selectionStrategyIsAll == null || + minimumConfirmations == null || + message == null || + amount == null || + address == null)) { + var res = await txHttpSend(wallet, selectionStrategyIsAll, + minimumConfirmations, message, amount, address); + result['result'] = res; + sendPort.send(result); + return; + } + } Logging.instance.log( "Error Arguments for $function not formatted correctly", @@ -717,32 +751,67 @@ class EpicCashWallet extends CoinServiceAPI { // TODO determine whether it is worth sending change to a change address. dynamic message; - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "createTransaction", - "wallet": wallet!, - "amount": txData['recipientAmt'], - "address": txData['addresss'], - "secretKeyIndex": 0, - "epicboxConfig": epicboxConfig!, - "minimumConfirmations": MINIMUM_CONFIRMATIONS, - }, name: walletName); - message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); + String receiverAddress = txData['addresss'] as String; + await m.protect(() async { + + if (receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://")) { + const int selectionStrategyIsAll = 0; + ReceivePort receivePort = await getIsolate({ + "function": "txHttpSend", + "wallet": wallet!, + "selectionStrategyIsAll": selectionStrategyIsAll, + "minimumConfirmations": MINIMUM_CONFIRMATIONS, + "message": "", + "amount": txData['recipientAmt'], + "address": txData['addresss'] + }, name: walletName); + + message = await receivePort.first; + if (message is String) { + Logging.instance + .log("this is a string $message", level: LogLevel.Error); + stop(receivePort); + throw Exception("txHttpSend isolate failed"); + } stop(receivePort); - throw Exception("createTransaction isolate failed"); + Logging.instance.log('Closing txHttpSend!\n $message', + level: LogLevel.Info); + + } else { + ReceivePort receivePort = await getIsolate({ + "function": "createTransaction", + "wallet": wallet!, + "amount": txData['recipientAmt'], + "address": txData['addresss'], + "secretKeyIndex": 0, + "epicboxConfig": epicboxConfig!, + "minimumConfirmations": MINIMUM_CONFIRMATIONS, + }, name: walletName); + + message = await receivePort.first; + if (message is String) { + Logging.instance + .log("this is a string $message", level: LogLevel.Error); + stop(receivePort); + throw Exception("createTransaction isolate failed"); + } + stop(receivePort); + Logging.instance.log('Closing createTransaction!\n $message', + level: LogLevel.Info); } - stop(receivePort); - Logging.instance.log('Closing createTransaction!\n $message', - level: LogLevel.Info); }); // return message; final String sendTx = message['result'] as String; - await putSendToAddresses(sendTx); + if (sendTx.contains("Error")) { + throw BadEpicHttpAddressException(message: sendTx); + } + + if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) { + await putSendToAddresses(sendTx); + } + Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info); @@ -752,11 +821,16 @@ class EpicCashWallet extends CoinServiceAPI { String errorMessage = decodeData[1] as String; throw Exception("Transaction failed with error code $errorMessage"); } else { - final postSlateRequest = decodeData[1]; - final postToServer = await postSlate( - txData['addresss'] as String, postSlateRequest as String); - Logging.instance - .log("POST_SLATE_IS $postToServer", level: LogLevel.Info); + + //If it's HTTP send no need to post to epicbox + if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) { + final postSlateRequest = decodeData[1]; + final postToServer = await postSlate( + txData['addresss'] as String, postSlateRequest as String); + Logging.instance + .log("POST_SLATE_IS $postToServer", level: LogLevel.Info); + } + final txCreateResult = decodeData[0]; // //TODO: second problem final transaction = json.decode(txCreateResult as String); @@ -2195,6 +2269,12 @@ class EpicCashWallet extends CoinServiceAPI { @override bool validateAddress(String address) { + if (address.startsWith("http://") || address.startsWith("https://")) { + if (Uri.tryParse(address) != null) { + return true; + } + } + String validate = validateSendAddress(address); if (int.parse(validate) == 1) { return true; From 9d68ffe6b29968d8aa4c55316b4522b5289dd5ed Mon Sep 17 00:00:00 2001 From: Likho Date: Thu, 1 Sep 2022 17:02:22 -0500 Subject: [PATCH 7/7] Fix HTTP send dart errors --- crypto_plugins/flutter_libepiccash | 2 +- lib/services/coins/epiccash/epiccash_wallet.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crypto_plugins/flutter_libepiccash b/crypto_plugins/flutter_libepiccash index 5ae20e71c..516fa886a 160000 --- a/crypto_plugins/flutter_libepiccash +++ b/crypto_plugins/flutter_libepiccash @@ -1 +1 @@ -Subproject commit 5ae20e71c0bb85952866fdd6aa7572438517943e +Subproject commit 516fa886ab5f94bbc32d29e50711bdccc9cbd154 diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index ee0d0aa2a..b57244009 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -807,9 +807,7 @@ class EpicCashWallet extends CoinServiceAPI { throw BadEpicHttpAddressException(message: sendTx); } - if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) { - await putSendToAddresses(sendTx); - } + await putSendToAddresses(sendTx); Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info); @@ -833,6 +831,8 @@ class EpicCashWallet extends CoinServiceAPI { final txCreateResult = decodeData[0]; // //TODO: second problem final transaction = json.decode(txCreateResult as String); + + Logger.print("TX_IS $transaction"); final tx = transaction[0]; final txLogEntry = json.decode(tx as String); final txLogEntryFirst = txLogEntry[0];