From d890662515ab1561877a45771d02a5f8c5954533 Mon Sep 17 00:00:00 2001 From: likho Date: Wed, 20 Sep 2023 16:12:48 +0200 Subject: [PATCH 01/29] WIP: Move Epiccash plugin calls to an abstract class --- .../crypto_currency/coins/epiccash.dart | 12 +++++++ lib/wallets/example/libepiccash.dart | 34 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index eb8d50682..81510f15d 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -32,4 +32,16 @@ class Epiccash extends Bip39Currency { return LibEpiccash.validateSendAddress(address: address); } + + String getMnemonic() { + return LibEpiccash.getMnemonic(); + } + + Future initializeNew(({String config, String mnemonic, String password, String name})? data) { + return LibEpiccash.initializeNewWallet( + config: data!.config, + mnemonic: data.mnemonic, + password: data.password, + name: data.name); + } } diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 1f7d45e59..2c0b80a76 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -1,4 +1,6 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash; +import 'package:tuple/tuple.dart'; /// /// Wrapped up calls to flutter_libepiccash. @@ -18,4 +20,36 @@ abstract class LibEpiccash { return false; } } + + static String getMnemonic() { + return lib_epiccash.walletMnemonic(); + } + + static Future _initializeWalletWrapper( + Tuple4 data) async { + final String initWalletStr = + lib_epiccash.initWallet(data.item1, data.item2, data.item3, data.item4); + return initWalletStr; + } + + static Future initializeNewWallet({ + required String config, + required String mnemonic, + required String password, + required String name}) async { + + String result = await compute( + _initializeWalletWrapper, + Tuple4( + config, + mnemonic, + password, + name, + ), + ); + + return result; + } + + } From 8ec22ed389b3d161a821ca0e37ab7c98652b13e3 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 20 Sep 2023 17:04:37 -0600 Subject: [PATCH 02/29] Added some notes/todos and changed usages of Tuple to using the new built in record type instead --- lib/wallets/example/libepiccash.dart | 48 ++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 2c0b80a76..ca7d44eef 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -1,6 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash; -import 'package:tuple/tuple.dart'; +import 'package:mutex/mutex.dart'; /// /// Wrapped up calls to flutter_libepiccash. @@ -21,35 +21,55 @@ abstract class LibEpiccash { } } + /// + /// Fetch the mnemonic of (some? current?) wallet + /// + // TODO: ensure the above documentation comment is correct + // TODO: ensure this will always return the mnemonic. If not, this function should throw an exception + // TODO: probably remove this as we don't use it in stack wallet. We store the mnemonic separately static String getMnemonic() { return lib_epiccash.walletMnemonic(); } + // Private function wrapper for compute static Future _initializeWalletWrapper( - Tuple4 data) async { - final String initWalletStr = - lib_epiccash.initWallet(data.item1, data.item2, data.item3, data.item4); + ({ + String config, + String mnemonic, + String password, + String name, + }) data, + ) async { + final String initWalletStr = lib_epiccash.initWallet( + data.config, + data.mnemonic, + data.password, + data.name, + ); return initWalletStr; } + /// + /// Create and or initialize a new epiccash wallet. + /// + // TODO: Complete/modify the documentation comment above + // TODO: Should return a void future. On error this function should throw and exception static Future initializeNewWallet({ required String config, required String mnemonic, required String password, - required String name}) async { - - String result = await compute( + required String name, + }) async { + final String result = await compute( _initializeWalletWrapper, - Tuple4( - config, - mnemonic, - password, - name, + ( + config: config, + mnemonic: mnemonic, + password: password, + name: name, ), ); return result; } - - } From 781e2262b5a0a5c7f183f1b675bfced5dba1f4e5 Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 20 Sep 2023 17:08:22 -0600 Subject: [PATCH 03/29] added mutex since only one epic cash wallet can/should be active at a time --- lib/wallets/example/libepiccash.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index ca7d44eef..525850acc 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -8,6 +8,11 @@ import 'package:mutex/mutex.dart'; /// Should all be static calls (no state stored in this class) /// abstract class LibEpiccash { + static final Mutex _mutex = Mutex(); + + /// + /// Check if [address] is a valid epiccash address according to libepiccash + /// static bool validateSendAddress({required String address}) { final String validate = lib_epiccash.validateSendAddress(address); if (int.parse(validate) == 1) { From 26feef9d83dd40285b46da7164cffcdb0b30ef24 Mon Sep 17 00:00:00 2001 From: julian-CStack Date: Fri, 22 Sep 2023 14:11:23 -0600 Subject: [PATCH 04/29] enititlements --- ios/Runner.xcodeproj/project.pbxproj | 9 +++++++-- ios/Runner/Runner.entitlements | 10 ++++++++++ macos/Runner/Release.entitlements | 6 ++++-- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 ios/Runner/Runner.entitlements diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 43e1486e6..fa0e9728d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B999088F2ABE1E170012A442 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; E6F536731AC506735EB76340 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -140,6 +141,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + B999088F2ABE1E170012A442 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -321,8 +323,8 @@ "${BUILT_PRODUCTS_DIR}/package_info_plus/package_info_plus.framework", "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", "${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", "${BUILT_PRODUCTS_DIR}/stack_wallet_backup/stack_wallet_backup.framework", + "${BUILT_PRODUCTS_DIR}/tor_ffi_plugin/tor_ffi_plugin.framework", "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", "${BUILT_PRODUCTS_DIR}/wakelock/wakelock.framework", ); @@ -354,8 +356,8 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/stack_wallet_backup.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/tor_ffi_plugin.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock.framework", ); @@ -455,6 +457,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -645,6 +648,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; @@ -727,6 +731,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 000000000..c326c8341 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements index 48271acc9..95f3da71e 100644 --- a/macos/Runner/Release.entitlements +++ b/macos/Runner/Release.entitlements @@ -4,7 +4,9 @@ com.apple.security.app-sandbox - com.apple.security.network.client - + com.apple.security.network.client + + com.apple.security.network.server + From 098a69eded1323f74769d651bf5ea9401f26bc41 Mon Sep 17 00:00:00 2001 From: likho Date: Tue, 26 Sep 2023 17:36:21 +0200 Subject: [PATCH 05/29] Move recover and wallet balances into abstract class --- .../crypto_currency/coins/epiccash.dart | 4 +- lib/wallets/example/libepiccash.dart | 106 ++++++++++++++++-- 2 files changed, 97 insertions(+), 13 deletions(-) diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 81510f15d..75ff3242a 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -37,8 +37,8 @@ class Epiccash extends Bip39Currency { return LibEpiccash.getMnemonic(); } - Future initializeNew(({String config, String mnemonic, String password, String name})? data) { - return LibEpiccash.initializeNewWallet( + Future createNewWallet(({String config, String mnemonic, String password, String name})? data) async { + await LibEpiccash.initializeNewWallet( config: data!.config, mnemonic: data.mnemonic, password: data.password, diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 525850acc..ecc73fb91 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -27,13 +27,18 @@ abstract class LibEpiccash { } /// - /// Fetch the mnemonic of (some? current?) wallet + /// Fetch the mnemonic For a new wallet (Only used in the example app) /// // TODO: ensure the above documentation comment is correct // TODO: ensure this will always return the mnemonic. If not, this function should throw an exception // TODO: probably remove this as we don't use it in stack wallet. We store the mnemonic separately static String getMnemonic() { - return lib_epiccash.walletMnemonic(); + try { + return lib_epiccash.walletMnemonic(); + } catch (e) { + throw Exception(e.toString()); + } + } // Private function wrapper for compute @@ -55,26 +60,105 @@ abstract class LibEpiccash { } /// - /// Create and or initialize a new epiccash wallet. + /// Create a new epiccash wallet. /// // TODO: Complete/modify the documentation comment above // TODO: Should return a void future. On error this function should throw and exception - static Future initializeNewWallet({ + static Future initializeNewWallet({ required String config, required String mnemonic, required String password, required String name, }) async { - final String result = await compute( - _initializeWalletWrapper, - ( + try { + await compute( + _initializeWalletWrapper, + ( config: config, mnemonic: mnemonic, password: password, name: name, - ), - ); - - return result; + ), + ); + } catch (e) { + throw("Error creating new wallet : ${e.toString()}"); + } } + + /// + /// Private function wrapper for wallet balances + /// + static Future _walletBalancesWrapper( + ({ + String wallet, + int refreshFromNode, + int minimumConfirmations + }) data,) async { + return lib_epiccash.getWalletInfo( + data.wallet, + data.refreshFromNode, + data.minimumConfirmations + ); + } + + /// + /// Get balance information for the currently open wallet + /// + static Future getWalletBalances({ + required String wallet, + required int refreshFromNode, + required int minimumConfirmations + }) async { + try { + String balances = await compute(_walletBalancesWrapper, ( + wallet: wallet, + refreshFromNode: refreshFromNode, + minimumConfirmations: minimumConfirmations, + )); + return balances; + } catch (e) { + throw("Error getting wallet info : ${e.toString()}"); + } + } + + /// + /// Private function wrapper for recover wallet function + /// + static Future _recoverWalletWrapper( + ({ + String config, + String password, + String mnemonic, + String name, + }) data,) async { + return lib_epiccash.recoverWallet( + data.config, + data.password, + data.mnemonic, + data.name, + ); + } + + /// + /// Recover an Epic wallet using a mnemonic + /// + static Future recoverWallet({ + required String config, + required String password, + required String mnemonic, + required String name + }) async { + try { + await compute(_recoverWalletWrapper, ( + config: config, + password: password, + mnemonic: mnemonic, + name: name, + )); + } catch (e) { + throw("Error recovering wallet : ${e.toString()}"); + } + } + + } From dc457e726632f518fdec7d23d57d915be8ba60c2 Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Tue, 26 Sep 2023 17:26:28 -0600 Subject: [PATCH 06/29] move scan outputs, create tx, get tx, cancel tx, and address info to abstract class --- .../crypto_currency/coins/epiccash.dart | 72 ++++- lib/wallets/example/libepiccash.dart | 249 ++++++++++++++---- 2 files changed, 275 insertions(+), 46 deletions(-) diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 75ff3242a..0f8ce1948 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -37,11 +37,81 @@ class Epiccash extends Bip39Currency { return LibEpiccash.getMnemonic(); } - Future createNewWallet(({String config, String mnemonic, String password, String name})? data) async { + Future createNewWallet( + ({ + String config, + String mnemonic, + String password, + String name, + })? data) async { await LibEpiccash.initializeNewWallet( config: data!.config, mnemonic: data.mnemonic, password: data.password, name: data.name); } + + Future scanOutputs( + ({String wallet, int startHeight, int numberOfBlocks})? data) async { + await LibEpiccash.scanOutputs( + wallet: data!.wallet, + startHeight: data.startHeight, + numberOfBlocks: data.numberOfBlocks, + ); + } + + Future createTransaction( + ({ + String wallet, + int amount, + String address, + int secretKey, + String epicboxConfig, + int minimumConfirmations, + String note, + })? data) async { + await LibEpiccash.createTransaction( + wallet: data!.wallet, + amount: data.amount, + address: data.address, + secretKey: data.secretKey, + epicboxConfig: data.epicboxConfig, + minimumConfirmations: data.minimumConfirmations, + note: data.note); + } + + Future getTransaction( + ({ + String wallet, + int refreshFromNode, + })? data) async { + await LibEpiccash.getTransaction( + wallet: data!.wallet, + refreshFromNode: data.refreshFromNode, + ); + } + + Future cancelTransaction( + ({ + String wallet, + String transactionId, + })? data) async { + await LibEpiccash.cancelTransaction( + wallet: data!.wallet, + transactionId: data.transactionId, + ); + } + + Future getAddressInfo( + ({ + String wallet, + int index, + String epicboxConfig, + })? data) async { + await LibEpiccash.getAddressInfo( + wallet: data!.wallet, + index: data.index, + epicboxConfig: data.epicboxConfig, + ); + } } diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index ecc73fb91..d10d54e04 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -38,7 +38,6 @@ abstract class LibEpiccash { } catch (e) { throw Exception(e.toString()); } - } // Private function wrapper for compute @@ -74,14 +73,14 @@ abstract class LibEpiccash { await compute( _initializeWalletWrapper, ( - config: config, - mnemonic: mnemonic, - password: password, - name: name, + config: config, + mnemonic: mnemonic, + password: password, + name: name, ), ); } catch (e) { - throw("Error creating new wallet : ${e.toString()}"); + throw ("Error creating new wallet : ${e.toString()}"); } } @@ -89,76 +88,236 @@ abstract class LibEpiccash { /// Private function wrapper for wallet balances /// static Future _walletBalancesWrapper( - ({ - String wallet, - int refreshFromNode, - int minimumConfirmations - }) data,) async { - return lib_epiccash.getWalletInfo( - data.wallet, - data.refreshFromNode, - data.minimumConfirmations - ); + ({String wallet, int refreshFromNode, int minimumConfirmations}) data, + ) async { + return lib_epiccash.getWalletInfo( + data.wallet, data.refreshFromNode, data.minimumConfirmations); } /// /// Get balance information for the currently open wallet /// - static Future getWalletBalances({ - required String wallet, - required int refreshFromNode, - required int minimumConfirmations - }) async { + static Future getWalletBalances( + {required String wallet, + required int refreshFromNode, + required int minimumConfirmations}) async { try { String balances = await compute(_walletBalancesWrapper, ( - wallet: wallet, - refreshFromNode: refreshFromNode, - minimumConfirmations: minimumConfirmations, + wallet: wallet, + refreshFromNode: refreshFromNode, + minimumConfirmations: minimumConfirmations, )); return balances; } catch (e) { - throw("Error getting wallet info : ${e.toString()}"); + throw ("Error getting wallet info : ${e.toString()}"); } } + /// + /// Private function wrapper for scanning output function + /// + static Future _scanOutputsWrapper( + ({String wallet, int startHeight, int numberOfBlocks}) data, + ) async { + return lib_epiccash.scanOutPuts( + data.wallet, + data.startHeight, + data.numberOfBlocks, + ); + } + + /// + /// Scan Epic outputs + /// + static Future scanOutputs({ + required String wallet, + required int startHeight, + required int numberOfBlocks, + }) async { + try { + await compute(_scanOutputsWrapper, ( + wallet: wallet, + startHeight: startHeight, + numberOfBlocks: numberOfBlocks, + )); + } catch (e) { + throw ("Error getting scanning outputs : ${e.toString()}"); + } + } + + /// + /// Private function wrapper for create transactions + /// + static Future _createTransactionWrapper( + ({ + String wallet, + int amount, + String address, + int secretKey, + String epicboxConfig, + int minimumConfirmations, + String note, + }) data, + ) async { + return lib_epiccash.createTransaction( + data.wallet, + data.amount, + data.address, + data.secretKey, + data.epicboxConfig, + data.minimumConfirmations, + data.note); + } + + /// + /// Create an Epic transaction + /// + static Future createTransaction({ + required String wallet, + required int amount, + required String address, + required int secretKey, + required String epicboxConfig, + required int minimumConfirmations, + required String note, + }) async { + try { + await compute(_createTransactionWrapper, ( + wallet: wallet, + amount: amount, + address: address, + secretKey: secretKey, + epicboxConfig: epicboxConfig, + minimumConfirmations: minimumConfirmations, + note: note, + )); + } catch (e) { + throw ("Error creating epic transaction : ${e.toString()}"); + } + } + + /// + /// Private function wrapper for get transactions + /// + static Future _getTransactionsWrapper( + ({ + String wallet, + int refreshFromNode, + }) data, + ) async { + return lib_epiccash.getTransactions( + data.wallet, + data.refreshFromNode, + ); + } + + /// + /// + /// + static Future getTransaction({ + required String wallet, + required int refreshFromNode, + }) async { + try { + await compute(_getTransactionsWrapper, ( + wallet: wallet, + refreshFromNode: refreshFromNode, + )); + } catch (e) { + throw ("Error getting epic transaction : ${e.toString()}"); + } + } + + /// + /// Private function for cancel transaction function + /// + static Future _cancelTransactionWrapper( + ({ + String wallet, + String transactionId, + }) data, + ) async { + return lib_epiccash.cancelTransaction( + data.wallet, + data.transactionId, + ); + } + + /// + /// + /// + static Future cancelTransaction({ + required String wallet, + required String transactionId, + }) async { + try { + await compute(_cancelTransactionWrapper, ( + wallet: wallet, + transactionId: transactionId, + )); + } catch (e) { + throw ("Error canceling epic transaction : ${e.toString()}"); + } + } + + static Future addressInfoWrapper( + ({ + String wallet, + int index, + String epicboxConfig, + }) data, + ) async { + return lib_epiccash.getAddressInfo( + data.wallet, + data.index, + data.epicboxConfig, + ); + } + + static Future getAddressInfo({ + required String wallet, + required int index, + required String epicboxConfig, + }) async { + try {} catch (e) {} + } + /// /// Private function wrapper for recover wallet function /// static Future _recoverWalletWrapper( - ({ + ({ String config, String password, String mnemonic, String name, - }) data,) async { - return lib_epiccash.recoverWallet( - data.config, - data.password, - data.mnemonic, - data.name, + }) data, + ) async { + return lib_epiccash.recoverWallet( + data.config, + data.password, + data.mnemonic, + data.name, ); } /// /// Recover an Epic wallet using a mnemonic /// - static Future recoverWallet({ - required String config, - required String password, - required String mnemonic, - required String name - }) async { + static Future recoverWallet( + {required String config, + required String password, + required String mnemonic, + required String name}) async { try { await compute(_recoverWalletWrapper, ( - config: config, - password: password, - mnemonic: mnemonic, - name: name, + config: config, + password: password, + mnemonic: mnemonic, + name: name, )); } catch (e) { - throw("Error recovering wallet : ${e.toString()}"); + throw ("Error recovering wallet : ${e.toString()}"); } } - - } From 13a171f3efa94357c7b78110bc1e7791351508a5 Mon Sep 17 00:00:00 2001 From: likho Date: Wed, 27 Sep 2023 17:53:10 +0200 Subject: [PATCH 07/29] WIP:Replace libepiccash calls with calls to abstract class, add error handling and return types other than strings --- .../coins/epiccash/epiccash_wallet.dart | 91 ++++--------------- .../crypto_currency/coins/epiccash.dart | 25 ++++- lib/wallets/example/libepiccash.dart | 31 ++++++- 3 files changed, 63 insertions(+), 84 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index bdf803e4b..c591a721f 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -48,14 +48,19 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; +import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; +import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; import 'package:tuple/tuple.dart'; import 'package:websocket_universal/websocket_universal.dart'; +import 'package:stackwallet/wallets/example/libepiccash.dart'; const int MINIMUM_CONFIRMATIONS = 3; const String GENESIS_HASH_MAINNET = ""; const String GENESIS_HASH_TESTNET = ""; +final epiccash = Epiccash(CryptoCurrencyNetwork.main); + class BadEpicHttpAddressException implements Exception { final String? message; @@ -383,34 +388,12 @@ class EpicCashWallet extends CoinServiceAPI return ""; } - Future allWalletBalances() async { + Future<({double awaitingFinalization, double pending, double spendable, double total})> allWalletBalances() async { final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 0; - - dynamic message; - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "getWalletInfo", - "wallet": wallet!, - "refreshFromNode": refreshFromNode, - "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("getWalletInfo isolate failed"); - } - stop(receivePort); - Logging.instance - .log('Closing getWalletInfo!\n $message', level: LogLevel.Info); - }); - - // return message; - final String walletBalances = message['result'] as String; - return walletBalances; + ({String wallet, int refreshFromNode, }) data = (wallet: wallet!, refreshFromNode: refreshFromNode); + var balances = await epiccash.getWalletInfo(data); + return balances; } Timer? timer; @@ -777,17 +760,8 @@ class EpicCashWallet extends CoinServiceAPI String name = _walletId; - await m.protect(() async { - await compute( - _initWalletWrapper, - Tuple4( - stringConfig, - mnemonicString, - password, - name, - ), - ); - }); + ({String config, String mnemonic, String password, String name,}) walletData = (config: stringConfig, mnemonic: mnemonicString, password: password, name: name); + await epiccash.createNewWallet(walletData); //Open wallet final walletOpen = openWallet(stringConfig, password); @@ -1830,27 +1804,7 @@ class EpicCashWallet extends CoinServiceAPI @override bool validateAddress(String address) { - //Invalid address that contains HTTP and epicbox domain - if ((address.startsWith("http://") || address.startsWith("https://")) && - address.contains("@")) { - return false; - } - if (address.startsWith("http://") || address.startsWith("https://")) { - if (Uri.tryParse(address) != null) { - return true; - } - } - - String validate = validateSendAddress(address); - if (int.parse(validate) == 1) { - //Check if address contrains a domain - if (address.contains("@")) { - return true; - } - return false; - } else { - return false; - } + return epiccash.validateAddress(address); } @override @@ -1905,26 +1859,14 @@ class EpicCashWallet extends CoinServiceAPI } Future _refreshBalance() async { - String walletBalances = await allWalletBalances(); - var jsonBalances = json.decode(walletBalances); - - final spendable = - (jsonBalances['amount_currently_spendable'] as double).toString(); - - final pending = - (jsonBalances['amount_awaiting_confirmation'] as double).toString(); - - final total = (jsonBalances['total'] as double).toString(); - final awaiting = - (jsonBalances['amount_awaiting_finalization'] as double).toString(); - + var balances = await allWalletBalances(); _balance = Balance( total: Amount.fromDecimal( - Decimal.parse(total) + Decimal.parse(awaiting), + Decimal.parse(balances.total.toString()) + Decimal.parse(balances.awaitingFinalization.toString()), fractionDigits: coin.decimals, ), spendable: Amount.fromDecimal( - Decimal.parse(spendable), + Decimal.parse(balances.spendable.toString()), fractionDigits: coin.decimals, ), blockedTotal: Amount( @@ -1932,11 +1874,10 @@ class EpicCashWallet extends CoinServiceAPI fractionDigits: coin.decimals, ), pendingSpendable: Amount.fromDecimal( - Decimal.parse(pending), + Decimal.parse(balances.pending.toString()), fractionDigits: coin.decimals, ), ); - await updateCachedBalance(_balance!); } diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 0f8ce1948..797179e5e 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -37,18 +37,36 @@ class Epiccash extends Bip39Currency { return LibEpiccash.getMnemonic(); } - Future createNewWallet( + Future createNewWallet( ({ String config, String mnemonic, String password, String name, })? data) async { - await LibEpiccash.initializeNewWallet( + String result = await LibEpiccash.initializeNewWallet( config: data!.config, mnemonic: data.mnemonic, password: data.password, name: data.name); + + if(result.isNotEmpty) { + return result; + } + return null; + + } + + Future<({double awaitingFinalization, double pending, double spendable, double total})> getWalletInfo( + ({ + String wallet, + int refreshFromNode, + })? data + ) async { + + var result = await LibEpiccash.getWalletBalances(wallet: data!.wallet, refreshFromNode: data.refreshFromNode, minimumConfirmations: minConfirms); + return result; + } Future scanOutputs( @@ -67,7 +85,6 @@ class Epiccash extends Bip39Currency { String address, int secretKey, String epicboxConfig, - int minimumConfirmations, String note, })? data) async { await LibEpiccash.createTransaction( @@ -76,7 +93,7 @@ class Epiccash extends Bip39Currency { address: data.address, secretKey: data.secretKey, epicboxConfig: data.epicboxConfig, - minimumConfirmations: data.minimumConfirmations, + minimumConfirmations: minConfirms, note: data.note); } diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index d10d54e04..acf48c3dd 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash; import 'package:mutex/mutex.dart'; @@ -34,7 +36,11 @@ abstract class LibEpiccash { // TODO: probably remove this as we don't use it in stack wallet. We store the mnemonic separately static String getMnemonic() { try { - return lib_epiccash.walletMnemonic(); + String mnemonic = lib_epiccash.walletMnemonic(); + if (mnemonic.isEmpty) { + throw Exception("Error getting mnemonic, returned empty string"); + } + return mnemonic; } catch (e) { throw Exception(e.toString()); } @@ -63,14 +69,14 @@ abstract class LibEpiccash { /// // TODO: Complete/modify the documentation comment above // TODO: Should return a void future. On error this function should throw and exception - static Future initializeNewWallet({ + static Future initializeNewWallet({ required String config, required String mnemonic, required String password, required String name, }) async { try { - await compute( + return await compute( _initializeWalletWrapper, ( config: config, @@ -97,7 +103,7 @@ abstract class LibEpiccash { /// /// Get balance information for the currently open wallet /// - static Future getWalletBalances( + static Future<({double awaitingFinalization, double pending, double spendable, double total})> getWalletBalances( {required String wallet, required int refreshFromNode, required int minimumConfirmations}) async { @@ -107,7 +113,22 @@ abstract class LibEpiccash { refreshFromNode: refreshFromNode, minimumConfirmations: minimumConfirmations, )); - return balances; + + //If balances is valid json return, else return error + if (balances.toUpperCase().contains("ERROR")) { + throw Exception(balances); + } + var jsonBalances = json.decode(balances); + //Return balances as record + ({ + double spendable, double pending, double total, double awaitingFinalization + }) balancesRecord = ( + spendable: jsonBalances['amount_currently_spendable'], + pending: jsonBalances['amount_awaiting_finalization'], + total: jsonBalances['total'], + awaitingFinalization: jsonBalances['amount_awaiting_finalization'], + ); + return balancesRecord; } catch (e) { throw ("Error getting wallet info : ${e.toString()}"); } From 9762ffd180e32f6520bf796845faadaefe286fca Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Wed, 27 Sep 2023 16:47:26 -0600 Subject: [PATCH 08/29] WIP: move get transaction fees, delete wallet, open wallet, and tx http send --- .../crypto_currency/coins/epiccash.dart | 156 ++++++++++--- lib/wallets/example/libepiccash.dart | 214 ++++++++++++++++-- 2 files changed, 321 insertions(+), 49 deletions(-) diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 797179e5e..921fdaaff 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -50,35 +50,40 @@ class Epiccash extends Bip39Currency { password: data.password, name: data.name); - if(result.isNotEmpty) { + if (result.isNotEmpty) { return result; } return null; - } - Future<({double awaitingFinalization, double pending, double spendable, double total})> getWalletInfo( - ({ - String wallet, - int refreshFromNode, - })? data - ) async { - - var result = await LibEpiccash.getWalletBalances(wallet: data!.wallet, refreshFromNode: data.refreshFromNode, minimumConfirmations: minConfirms); + Future<({double awaitingFinalization, double pending, double spendable, double total})> + getWalletInfo( + ({ + String wallet, + int refreshFromNode, + })? data) async { + var result = await LibEpiccash.getWalletBalances( + wallet: data!.wallet, + refreshFromNode: data.refreshFromNode, + minimumConfirmations: minConfirms); return result; - } - Future scanOutputs( + Future scanOutputs( ({String wallet, int startHeight, int numberOfBlocks})? data) async { - await LibEpiccash.scanOutputs( + var result = await LibEpiccash.scanOutputs( wallet: data!.wallet, startHeight: data.startHeight, numberOfBlocks: data.numberOfBlocks, ); + + if (result.isNotEmpty) { + return result; + } + return null; } - Future createTransaction( + Future createTransaction( ({ String wallet, int amount, @@ -87,48 +92,143 @@ class Epiccash extends Bip39Currency { String epicboxConfig, String note, })? data) async { - await LibEpiccash.createTransaction( - wallet: data!.wallet, - amount: data.amount, - address: data.address, - secretKey: data.secretKey, - epicboxConfig: data.epicboxConfig, - minimumConfirmations: minConfirms, - note: data.note); + var result = await LibEpiccash.createTransaction( + wallet: data!.wallet, + amount: data.amount, + address: data.address, + secretKey: data.secretKey, + epicboxConfig: data.epicboxConfig, + minimumConfirmations: minConfirms, + note: data.note, + ); + + if (result.isNotEmpty) { + return result; + } + return null; } - Future getTransaction( + Future getTransaction( ({ String wallet, int refreshFromNode, })? data) async { - await LibEpiccash.getTransaction( + var result = await LibEpiccash.getTransaction( wallet: data!.wallet, refreshFromNode: data.refreshFromNode, ); + + if (result.isNotEmpty) { + return result; + } + return null; } - Future cancelTransaction( + Future cancelTransaction( ({ String wallet, String transactionId, })? data) async { - await LibEpiccash.cancelTransaction( + var result = await LibEpiccash.cancelTransaction( wallet: data!.wallet, transactionId: data.transactionId, ); + + if (result.isNotEmpty) { + return result; + } + return null; } - Future getAddressInfo( + Future getAddressInfo( ({ String wallet, int index, String epicboxConfig, })? data) async { - await LibEpiccash.getAddressInfo( + var result = await LibEpiccash.getAddressInfo( wallet: data!.wallet, index: data.index, epicboxConfig: data.epicboxConfig, ); + + if (result.isNotEmpty) { + return result; + } + return null; + } + + static Future transactionFees( + ({ + String wallet, + int amount, + int minimumConfirmations, + })? data, + ) async { + var result = await LibEpiccash.getTransactionFees( + wallet: data!.wallet, + amount: data.amount, + minimumConfirmations: data.minimumConfirmations, + ); + if (result.isNotEmpty) { + return result; + } + return null; + } + + static Future deleteWallet( + ({ + String wallet, + String config, + })? data, + ) async { + var result = await LibEpiccash.deleteWallet( + wallet: data!.wallet, + config: data.config, + ); + if (result.isNotEmpty) { + return result; + } + return null; + } + + static Future openWallet( + ({ + String config, + String password, + })? data, + ) async { + var result = await LibEpiccash.openWallet( + config: data!.config, + password: data.password, + ); + if (result.isNotEmpty) { + return result; + } + return null; + } + + static Future txHttpSend( + ({ + String wallet, + int selectionStrategyIsAll, + int minimumConfirmations, + String message, + int amount, + String address, + })? data, + ) async { + var result = await LibEpiccash.txHttpSend( + wallet: data!.wallet, + selectionStrategyIsAll: data.selectionStrategyIsAll, + minimumConfirmations: data.minimumConfirmations, + message: data.message, + amount: data.amount, + address: data.address, + ); + if (result.isNotEmpty) { + return result; + } + return null; } } diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index acf48c3dd..74fb278f3 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -103,10 +103,17 @@ abstract class LibEpiccash { /// /// Get balance information for the currently open wallet /// - static Future<({double awaitingFinalization, double pending, double spendable, double total})> getWalletBalances( - {required String wallet, - required int refreshFromNode, - required int minimumConfirmations}) async { + static Future< + ({ + double awaitingFinalization, + double pending, + double spendable, + double total + })> + getWalletBalances( + {required String wallet, + required int refreshFromNode, + required int minimumConfirmations}) async { try { String balances = await compute(_walletBalancesWrapper, ( wallet: wallet, @@ -121,12 +128,15 @@ abstract class LibEpiccash { var jsonBalances = json.decode(balances); //Return balances as record ({ - double spendable, double pending, double total, double awaitingFinalization + double spendable, + double pending, + double total, + double awaitingFinalization }) balancesRecord = ( - spendable: jsonBalances['amount_currently_spendable'], - pending: jsonBalances['amount_awaiting_finalization'], - total: jsonBalances['total'], - awaitingFinalization: jsonBalances['amount_awaiting_finalization'], + spendable: jsonBalances['amount_currently_spendable'], + pending: jsonBalances['amount_awaiting_finalization'], + total: jsonBalances['total'], + awaitingFinalization: jsonBalances['amount_awaiting_finalization'], ); return balancesRecord; } catch (e) { @@ -150,13 +160,13 @@ abstract class LibEpiccash { /// /// Scan Epic outputs /// - static Future scanOutputs({ + static Future scanOutputs({ required String wallet, required int startHeight, required int numberOfBlocks, }) async { try { - await compute(_scanOutputsWrapper, ( + return await compute(_scanOutputsWrapper, ( wallet: wallet, startHeight: startHeight, numberOfBlocks: numberOfBlocks, @@ -193,7 +203,7 @@ abstract class LibEpiccash { /// /// Create an Epic transaction /// - static Future createTransaction({ + static Future createTransaction({ required String wallet, required int amount, required String address, @@ -203,7 +213,7 @@ abstract class LibEpiccash { required String note, }) async { try { - await compute(_createTransactionWrapper, ( + return await compute(_createTransactionWrapper, ( wallet: wallet, amount: amount, address: address, @@ -235,12 +245,12 @@ abstract class LibEpiccash { /// /// /// - static Future getTransaction({ + static Future getTransaction({ required String wallet, required int refreshFromNode, }) async { try { - await compute(_getTransactionsWrapper, ( + return await compute(_getTransactionsWrapper, ( wallet: wallet, refreshFromNode: refreshFromNode, )); @@ -265,14 +275,14 @@ abstract class LibEpiccash { } /// + /// Cancel current Epic transaction /// - /// - static Future cancelTransaction({ + static Future cancelTransaction({ required String wallet, required String transactionId, }) async { try { - await compute(_cancelTransactionWrapper, ( + return await compute(_cancelTransactionWrapper, ( wallet: wallet, transactionId: transactionId, )); @@ -281,7 +291,10 @@ abstract class LibEpiccash { } } - static Future addressInfoWrapper( + /// + /// Private function for address info function + /// + static Future _addressInfoWrapper( ({ String wallet, int index, @@ -295,12 +308,59 @@ abstract class LibEpiccash { ); } - static Future getAddressInfo({ + /// + /// get Epic address info + /// + static Future getAddressInfo({ required String wallet, required int index, required String epicboxConfig, }) async { - try {} catch (e) {} + try { + return await compute(_addressInfoWrapper, ( + wallet: wallet, + index: index, + epicboxConfig: epicboxConfig, + )); + } catch (e) { + throw ("Error getting address info : ${e.toString()}"); + } + } + + /// + /// Private function for getting transaction fees + /// + static Future _transactionFeesWrapper( + ({ + String wallet, + int amount, + int minimumConfirmations, + }) data, + ) async { + return lib_epiccash.getTransactionFees( + data.wallet, + data.amount, + data.minimumConfirmations, + ); + } + + /// + /// get transaction fees for Epic + /// + static Future getTransactionFees({ + required String wallet, + required int amount, + required int minimumConfirmations, + }) async { + try { + return await compute(_transactionFeesWrapper, ( + wallet: wallet, + amount: amount, + minimumConfirmations: minimumConfirmations, + )); + } catch (e) { + throw ("Error getting transaction fees : ${e.toString()}"); + } } /// @@ -341,4 +401,116 @@ abstract class LibEpiccash { throw ("Error recovering wallet : ${e.toString()}"); } } + + /// + /// Private function wrapper for delete wallet function + /// + static Future _deleteWalletWrapper( + ({ + String wallet, + String config, + }) data, + ) async { + return lib_epiccash.deleteWallet( + data.wallet, + data.config, + ); + } + + /// + /// Delete an Epic wallet + /// + static Future deleteWallet({ + required String wallet, + required String config, + }) async { + try { + return await compute(_deleteWalletWrapper, ( + wallet: wallet, + config: config, + )); + } catch (e) { + throw ("Error deleting wallet : ${e.toString()}"); + } + } + + /// + /// Private function wrapper for open wallet function + /// + static Future _openWalletWrapper( + ({ + String config, + String password, + }) data, + ) async { + return lib_epiccash.openWallet( + data.config, + data.password, + ); + } + + /// + /// Open an Epic wallet + /// + static Future openWallet({ + required String config, + required String password, + }) async { + try { + return await compute(_openWalletWrapper, ( + config: config, + password: password, + )); + } catch (e) { + throw ("Error opening wallet : ${e.toString()}"); + } + } + + /// + /// Private function for txHttpSend function + /// + static Future _txHttpSendWrapper( + ({ + String wallet, + int selectionStrategyIsAll, + int minimumConfirmations, + String message, + int amount, + String address, + }) data, + ) async { + return lib_epiccash.txHttpSend( + data.wallet, + data.selectionStrategyIsAll, + data.minimumConfirmations, + data.message, + data.amount, + data.address, + ); + } + + /// + /// + /// + static Future txHttpSend({ + required String wallet, + required int selectionStrategyIsAll, + required int minimumConfirmations, + required String message, + required int amount, + required String address, + }) async { + try { + return await compute(_txHttpSendWrapper, ( + wallet: wallet, + selectionStrategyIsAll: selectionStrategyIsAll, + minimumConfirmations: minimumConfirmations, + message: message, + amount: amount, + address: address, + )); + } catch (e) { + throw ("Error sending tx HTTP : ${e.toString()}"); + } + } } From 835d27dc386fc3016d19275c0905737e7116fa31 Mon Sep 17 00:00:00 2001 From: likho Date: Thu, 28 Sep 2023 16:11:41 +0200 Subject: [PATCH 09/29] WIP: Epicwallet clean up, get fees and address from abstract class --- .../coins/epiccash/epiccash_wallet.dart | 165 ++---------------- .../crypto_currency/coins/epiccash.dart | 18 +- lib/wallets/example/libepiccash.dart | 62 ++++++- 3 files changed, 76 insertions(+), 169 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index c591a721f..9b42b5d1e 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -108,20 +108,6 @@ Future executeNative(Map arguments) async { sendPort.send(result); return; } - } else if (function == "getWalletInfo") { - final wallet = arguments['wallet'] as String?; - final refreshFromNode = arguments['refreshFromNode'] as int?; - final minimumConfirmations = arguments['minimumConfirmations'] as int?; - Map result = {}; - if (!(wallet == null || - refreshFromNode == null || - minimumConfirmations == null)) { - var res = - await getWalletInfo(wallet, refreshFromNode, minimumConfirmations); - result['result'] = res; - sendPort.send(result); - return; - } } else if (function == "getTransactions") { final wallet = arguments['wallet'] as String?; final refreshFromNode = arguments['refreshFromNode'] as int?; @@ -142,18 +128,6 @@ Future executeNative(Map arguments) async { sendPort.send(result); return; } - } else if (function == "getTransactionFees") { - final wallet = arguments['wallet'] as String?; - final amount = arguments['amount'] as int?; - final minimumConfirmations = arguments['minimumConfirmations'] as int?; - Map result = {}; - if (!(wallet == null || amount == null || minimumConfirmations == null)) { - var res = - await getTransactionFees(wallet, amount, minimumConfirmations); - result['result'] = res; - sendPort.send(result); - return; - } } else if (function == "createTransaction") { final wallet = arguments['wallet'] as String?; final amount = arguments['amount'] as int?; @@ -274,12 +248,6 @@ Future _initWalletWrapper( return initWalletStr; } -Future _initGetAddressInfoWrapper( - Tuple3 data) async { - String walletAddress = getAddressInfo(data.item1, data.item2, data.item3); - return walletAddress; -} - Future _walletMnemonicWrapper(int throwaway) async { final String mnemonic = walletMnemonic(); return mnemonic; @@ -553,13 +521,10 @@ class EpicCashWallet extends CoinServiceAPI final wallet = await _secureStore.read(key: '${_walletId}_wallet'); EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); - String? walletAddress; - await m.protect(() async { - walletAddress = await compute( - _initGetAddressInfoWrapper, - Tuple3(wallet!, index, epicboxConfig.toString()), - ); - }); + ({String wallet, int index, String epicboxConfig}) data = (wallet: wallet!, index: index, epicboxConfig: epicboxConfig.toString()); + + String? walletAddress = await epiccash.getAddressInfo(data); + Logging.instance .log("WALLET_ADDRESS_IS $walletAddress", level: LogLevel.Info); @@ -705,20 +670,14 @@ class EpicCashWallet extends CoinServiceAPI Logging.instance.log("This index is $index", level: LogLevel.Info); EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); - String? walletAddress; - await m.protect(() async { - walletAddress = await compute( - _initGetAddressInfoWrapper, - Tuple3(wallet!, index, epicboxConfig.toString()), - ); - }); + + ({String wallet, int index, String epicboxConfig}) data = (wallet: wallet!, index: index, epicboxConfig: epicboxConfig.toString()); + String? walletAddress = await epiccash.getAddressInfo(data); + Logging.instance .log("WALLET_ADDRESS_IS $walletAddress", level: LogLevel.Info); - Logging.instance - .log("Wallet address is $walletAddress", level: LogLevel.Info); - String addressInfo = walletAddress!; await _secureStore.write( - key: '${_walletId}_address_info', value: addressInfo); + key: '${_walletId}_address_info', value: walletAddress); } // TODO: make more robust estimate of date maybe using https://explorer.epic.tech/api-index @@ -861,120 +820,20 @@ class EpicCashWallet extends CoinServiceAPI Future nativeFee(int satoshiAmount, {bool ifErrorEstimateFee = false}) async { final wallet = await _secureStore.read(key: '${_walletId}_wallet'); - try { - String? transactionFees; - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "getTransactionFees", - "wallet": wallet!, - "amount": satoshiAmount, - "minimumConfirmations": MINIMUM_CONFIRMATIONS, - }, name: walletName); - - var message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("getTransactionFees isolate failed"); - } - stop(receivePort); - Logging.instance.log('Closing getTransactionFees!\n $message', - level: LogLevel.Info); - // return message; - transactionFees = message['result'] as String; - }); - debugPrint(transactionFees); - dynamic decodeData; final available = balance.spendable.raw.toInt(); + ({String wallet, int amount, int availableAmount}) data = (wallet: wallet!, amount: satoshiAmount, availableAmount: available); + var transactionFees = await epiccash.transactionFees(data); - if (available == satoshiAmount) { - if (transactionFees!.contains("Required")) { - var splits = transactionFees!.split(" "); - Decimal required = Decimal.zero; - Decimal available = Decimal.zero; - for (int i = 0; i < splits.length; i++) { - var word = splits[i]; - if (word == "Required:") { - required = Decimal.parse(splits[i + 1].replaceAll(",", "")); - } else if (word == "Available:") { - available = Decimal.parse(splits[i + 1].replaceAll(",", "")); - } - } - int largestSatoshiFee = - ((required - available) * Decimal.fromInt(100000000)) - .toBigInt() - .toInt(); - var amountSending = satoshiAmount - largestSatoshiFee; - - //Get fees for this new amount - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "getTransactionFees", - "wallet": wallet!, - "amount": amountSending, - "minimumConfirmations": MINIMUM_CONFIRMATIONS, - }, name: walletName); - - var message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("getTransactionFees isolate failed"); - } - stop(receivePort); - Logging.instance.log('Closing getTransactionFees!\n $message', - level: LogLevel.Info); - // return message; - transactionFees = message['result'] as String; - }); - } - decodeData = json.decode(transactionFees!); - } else { - try { - decodeData = json.decode(transactionFees!); - } catch (e) { - if (ifErrorEstimateFee) { - //Error Not enough funds. Required: 0.56500000, Available: 0.56200000 - if (transactionFees!.contains("Required")) { - var splits = transactionFees!.split(" "); - Decimal required = Decimal.zero; - Decimal available = Decimal.zero; - for (int i = 0; i < splits.length; i++) { - var word = splits[i]; - if (word == "Required:") { - required = Decimal.parse(splits[i + 1].replaceAll(",", "")); - } else if (word == "Available:") { - available = Decimal.parse(splits[i + 1].replaceAll(",", "")); - } - } - int largestSatoshiFee = - ((required - available) * Decimal.fromInt(100000000)) - .toBigInt() - .toInt(); - Logging.instance.log("largestSatoshiFee $largestSatoshiFee", - level: LogLevel.Info); - return largestSatoshiFee; - } - } - rethrow; - } - } - - //TODO: first problem int realfee = 0; try { - var txObject = decodeData[0]; realfee = - (Decimal.parse(txObject["fee"].toString())).toBigInt().toInt(); + (Decimal.parse(transactionFees.fee.toString())).toBigInt().toInt(); } catch (e, s) { //todo: come back to this debugPrint("$e $s"); } - return realfee; } catch (e, s) { Logging.instance.log("Error getting fees $e - $s", level: LogLevel.Error); diff --git a/lib/wallets/crypto_currency/coins/epiccash.dart b/lib/wallets/crypto_currency/coins/epiccash.dart index 921fdaaff..b0e53797e 100644 --- a/lib/wallets/crypto_currency/coins/epiccash.dart +++ b/lib/wallets/crypto_currency/coins/epiccash.dart @@ -158,25 +158,23 @@ class Epiccash extends Bip39Currency { return null; } - static Future transactionFees( + Future<({int fee, bool strategyUseAll, int total})> transactionFees( ({ String wallet, int amount, - int minimumConfirmations, + int availableAmount, })? data, ) async { var result = await LibEpiccash.getTransactionFees( wallet: data!.wallet, amount: data.amount, - minimumConfirmations: data.minimumConfirmations, + minimumConfirmations: minConfirms, + available: data.availableAmount, ); - if (result.isNotEmpty) { - return result; - } - return null; + return result; } - static Future deleteWallet( + Future deleteWallet( ({ String wallet, String config, @@ -192,7 +190,7 @@ class Epiccash extends Bip39Currency { return null; } - static Future openWallet( + Future openWallet( ({ String config, String password, @@ -208,7 +206,7 @@ class Epiccash extends Bip39Currency { return null; } - static Future txHttpSend( + Future txHttpSend( ({ String wallet, int selectionStrategyIsAll, diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 74fb278f3..3fff124e0 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash; import 'package:mutex/mutex.dart'; @@ -347,19 +348,68 @@ abstract class LibEpiccash { /// /// get transaction fees for Epic /// - static Future getTransactionFees({ + static Future<({int fee, bool strategyUseAll, int total})> getTransactionFees({ required String wallet, required int amount, required int minimumConfirmations, + required int available, }) async { try { - return await compute(_transactionFeesWrapper, ( - wallet: wallet, - amount: amount, - minimumConfirmations: minimumConfirmations, + + String fees = await compute(_transactionFeesWrapper, ( + wallet: wallet, + amount: amount, + minimumConfirmations: minimumConfirmations, )); + + if (available == amount) { + if (fees.contains("Required")) { + var splits = fees.split(" "); + Decimal required = Decimal.zero; + Decimal available = Decimal.zero; + for (int i = 0; i < splits.length; i++) { + var word = splits[i]; + if (word == "Required:") { + required = Decimal.parse(splits[i + 1].replaceAll(",", "")); + } else if (word == "Available:") { + available = Decimal.parse(splits[i + 1].replaceAll(",", "")); + } + } + int largestSatoshiFee = + ((required - available) * Decimal.fromInt(100000000)) + .toBigInt() + .toInt(); + var amountSending = amount - largestSatoshiFee; + //Get fees for this new amount + ({String wallet, int amount, }) data = (wallet: wallet, amount: amountSending); + fees = await compute(_transactionFeesWrapper, ( + wallet: wallet, + amount: amountSending, + minimumConfirmations: minimumConfirmations, + )); + } + } + + + if (fees.toUpperCase().contains("ERROR")) { + //Check if the error is an + //Throw the returned error + throw Exception(fees); + } + var decodedFees = json.decode(fees); + var feeItem = decodedFees[0]; + ({ + bool strategyUseAll, + int total, + int fee, + }) feeRecord = ( + strategyUseAll: feeItem['selection_strategy_is_use_all'], + total: feeItem['total'], + fee: feeItem['fee'], + ); + return feeRecord; } catch (e) { - throw ("Error getting transaction fees : ${e.toString()}"); + throw (e.toString()); } } From 3dd8083a09ce09e5f9bc9d00eccf2799d1e07f14 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 28 Sep 2023 10:05:18 -0600 Subject: [PATCH 10/29] call abstract wrapper class functions directly --- .../coins/epiccash/epiccash_wallet.dart | 66 ++++++++++++++----- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 9b42b5d1e..aae3343e7 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -48,19 +48,15 @@ import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/stack_file_system.dart'; import 'package:stackwallet/utilities/test_epic_box_connection.dart'; -import 'package:stackwallet/wallets/crypto_currency/coins/epiccash.dart'; -import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart'; +import 'package:stackwallet/wallets/example/libepiccash.dart' as epiccash; import 'package:tuple/tuple.dart'; import 'package:websocket_universal/websocket_universal.dart'; -import 'package:stackwallet/wallets/example/libepiccash.dart'; const int MINIMUM_CONFIRMATIONS = 3; const String GENESIS_HASH_MAINNET = ""; const String GENESIS_HASH_TESTNET = ""; -final epiccash = Epiccash(CryptoCurrencyNetwork.main); - class BadEpicHttpAddressException implements Exception { final String? message; @@ -356,12 +352,20 @@ class EpicCashWallet extends CoinServiceAPI return ""; } - Future<({double awaitingFinalization, double pending, double spendable, double total})> allWalletBalances() async { + Future< + ({ + double awaitingFinalization, + double pending, + double spendable, + double total + })> allWalletBalances() async { final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 0; - ({String wallet, int refreshFromNode, }) data = (wallet: wallet!, refreshFromNode: refreshFromNode); - var balances = await epiccash.getWalletInfo(data); - return balances; + return await epiccash.LibEpiccash.getWalletBalances( + wallet: wallet!, + refreshFromNode: refreshFromNode, + minimumConfirmations: MINIMUM_CONFIRMATIONS, + ); } Timer? timer; @@ -521,7 +525,11 @@ class EpicCashWallet extends CoinServiceAPI final wallet = await _secureStore.read(key: '${_walletId}_wallet'); EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); - ({String wallet, int index, String epicboxConfig}) data = (wallet: wallet!, index: index, epicboxConfig: epicboxConfig.toString()); + ({String wallet, int index, String epicboxConfig}) data = ( + wallet: wallet!, + index: index, + epicboxConfig: epicboxConfig.toString() + ); String? walletAddress = await epiccash.getAddressInfo(data); @@ -670,8 +678,11 @@ class EpicCashWallet extends CoinServiceAPI Logging.instance.log("This index is $index", level: LogLevel.Info); EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); - - ({String wallet, int index, String epicboxConfig}) data = (wallet: wallet!, index: index, epicboxConfig: epicboxConfig.toString()); + ({String wallet, int index, String epicboxConfig}) data = ( + wallet: wallet!, + index: index, + epicboxConfig: epicboxConfig.toString() + ); String? walletAddress = await epiccash.getAddressInfo(data); Logging.instance @@ -719,7 +730,17 @@ class EpicCashWallet extends CoinServiceAPI String name = _walletId; - ({String config, String mnemonic, String password, String name,}) walletData = (config: stringConfig, mnemonic: mnemonicString, password: password, name: name); + ({ + String config, + String mnemonic, + String password, + String name, + }) walletData = ( + config: stringConfig, + mnemonic: mnemonicString, + password: password, + name: name + ); await epiccash.createNewWallet(walletData); //Open wallet @@ -821,9 +842,9 @@ class EpicCashWallet extends CoinServiceAPI {bool ifErrorEstimateFee = false}) async { final wallet = await _secureStore.read(key: '${_walletId}_wallet'); try { - final available = balance.spendable.raw.toInt(); - ({String wallet, int amount, int availableAmount}) data = (wallet: wallet!, amount: satoshiAmount, availableAmount: available); + ({String wallet, int amount, int availableAmount}) data = + (wallet: wallet!, amount: satoshiAmount, availableAmount: available); var transactionFees = await epiccash.transactionFees(data); int realfee = 0; @@ -1663,7 +1684,17 @@ class EpicCashWallet extends CoinServiceAPI @override bool validateAddress(String address) { - return epiccash.validateAddress(address); + // Invalid address that contains HTTP and epicbox domain + if ((address.startsWith("http://") || address.startsWith("https://")) && + address.contains("@")) { + return false; + } + if (address.startsWith("http://") || address.startsWith("https://")) { + if (Uri.tryParse(address) != null) { + return true; + } + } + return epiccash.LibEpiccash.validateSendAddress(address: address); } @override @@ -1721,7 +1752,8 @@ class EpicCashWallet extends CoinServiceAPI var balances = await allWalletBalances(); _balance = Balance( total: Amount.fromDecimal( - Decimal.parse(balances.total.toString()) + Decimal.parse(balances.awaitingFinalization.toString()), + Decimal.parse(balances.total.toString()) + + Decimal.parse(balances.awaitingFinalization.toString()), fractionDigits: coin.decimals, ), spendable: Amount.fromDecimal( From 5c726a639c036a885188f8213ba31cc15615ce05 Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Thu, 28 Sep 2023 16:22:24 -0600 Subject: [PATCH 11/29] WIP: call abstract wrapper class for addressInfo, openWallet, deleteWallet, chainHeight --- .../coins/epiccash/epiccash_wallet.dart | 48 ++++++++++----- lib/wallets/example/libepiccash.dart | 58 +++++++++++++------ 2 files changed, 71 insertions(+), 35 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index aae3343e7..b15b2673d 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -202,10 +202,6 @@ Future _cancelTransactionWrapper(Tuple2 data) async { return cancelTransaction(data.item1, data.item2); } -Future _deleteWalletWrapper(Tuple2 data) async { - return deleteWallet(data.item1, data.item2); -} - Future deleteEpicWallet({ required String walletId, required SecureStorageInterface secureStore, @@ -229,7 +225,7 @@ Future deleteEpicWallet({ return "Tried to delete non existent epic wallet file with walletId=$walletId"; } else { try { - return _deleteWalletWrapper(Tuple2(wallet, config!)); + return epiccash.LibEpiccash.deleteWallet(wallet: wallet, config: config!); } catch (e, s) { Logging.instance.log("$e\n$s", level: LogLevel.Error); return "deleteEpicWallet($walletId) failed..."; @@ -531,7 +527,11 @@ class EpicCashWallet extends CoinServiceAPI epicboxConfig: epicboxConfig.toString() ); - String? walletAddress = await epiccash.getAddressInfo(data); + String? walletAddress = await epiccash.LibEpiccash.getAddressInfo( + wallet: wallet, + index: index, + epicboxConfig: epicboxConfig.toString(), + ); Logging.instance .log("WALLET_ADDRESS_IS $walletAddress", level: LogLevel.Info); @@ -656,7 +656,8 @@ class EpicCashWallet extends CoinServiceAPI final config = await getRealConfig(); final password = await _secureStore.read(key: '${_walletId}_password'); - final walletOpen = openWallet(config, password!); + final walletOpen = await epiccash.LibEpiccash.openWallet( + config: config, password: password!); await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen); if (getCachedId() == null) { @@ -683,7 +684,11 @@ class EpicCashWallet extends CoinServiceAPI index: index, epicboxConfig: epicboxConfig.toString() ); - String? walletAddress = await epiccash.getAddressInfo(data); + String? walletAddress = await epiccash.LibEpiccash.getAddressInfo( + wallet: wallet, + index: index, + epicboxConfig: epicboxConfig.toString(), + ); Logging.instance .log("WALLET_ADDRESS_IS $walletAddress", level: LogLevel.Info); @@ -741,10 +746,16 @@ class EpicCashWallet extends CoinServiceAPI password: password, name: name ); - await epiccash.createNewWallet(walletData); + await epiccash.LibEpiccash.initializeNewWallet( + config: stringConfig, + mnemonic: mnemonicString, + password: password, + name: name, + ); //Open wallet - final walletOpen = openWallet(stringConfig, password); + final walletOpen = await epiccash.LibEpiccash.openWallet( + config: stringConfig, password: password); await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen); //Store Epic box address info @@ -845,7 +856,13 @@ class EpicCashWallet extends CoinServiceAPI final available = balance.spendable.raw.toInt(); ({String wallet, int amount, int availableAmount}) data = (wallet: wallet!, amount: satoshiAmount, availableAmount: available); - var transactionFees = await epiccash.transactionFees(data); + var transactionFees = await epiccash.LibEpiccash.getTransactionFees( + wallet: wallet, + amount: satoshiAmount, + // todo: double check + minimumConfirmations: MINIMUM_CONFIRMATIONS, + available: available, + ); int realfee = 0; try { @@ -1165,7 +1182,8 @@ class EpicCashWallet extends CoinServiceAPI ]); //Open Wallet - final walletOpen = openWallet(stringConfig, password); + final walletOpen = await epiccash.LibEpiccash.openWallet( + config: stringConfig, password: password); await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen); //Store Epic box address info @@ -1195,10 +1213,8 @@ class EpicCashWallet extends CoinServiceAPI final config = await getRealConfig(); int? latestHeight; await m.protect(() async { - latestHeight = await compute( - _getChainHeightWrapper, - config, - ); + latestHeight = + await epiccash.LibEpiccash.getChainHeight(config: config); }); await updateCachedChainHeight(latestHeight!); diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 3fff124e0..8e51e0049 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -292,6 +292,24 @@ abstract class LibEpiccash { } } + static Future _chainHeightWrapper( + ({ + String config, + }) data, + ) async { + return lib_epiccash.getChainHeight(data.config); + } + + static Future getChainHeight({ + required String config, + }) async { + try { + return await compute(_chainHeightWrapper, (config: config,)); + } catch (e) { + throw ("Error getting chain height : ${e.toString()}"); + } + } + /// /// Private function for address info function /// @@ -348,18 +366,18 @@ abstract class LibEpiccash { /// /// get transaction fees for Epic /// - static Future<({int fee, bool strategyUseAll, int total})> getTransactionFees({ + static Future<({int fee, bool strategyUseAll, int total})> + getTransactionFees({ required String wallet, required int amount, required int minimumConfirmations, required int available, }) async { try { - String fees = await compute(_transactionFeesWrapper, ( - wallet: wallet, - amount: amount, - minimumConfirmations: minimumConfirmations, + wallet: wallet, + amount: amount, + minimumConfirmations: minimumConfirmations, )); if (available == amount) { @@ -376,21 +394,23 @@ abstract class LibEpiccash { } } int largestSatoshiFee = - ((required - available) * Decimal.fromInt(100000000)) - .toBigInt() - .toInt(); + ((required - available) * Decimal.fromInt(100000000)) + .toBigInt() + .toInt(); var amountSending = amount - largestSatoshiFee; //Get fees for this new amount - ({String wallet, int amount, }) data = (wallet: wallet, amount: amountSending); + ({ + String wallet, + int amount, + }) data = (wallet: wallet, amount: amountSending); fees = await compute(_transactionFeesWrapper, ( - wallet: wallet, - amount: amountSending, - minimumConfirmations: minimumConfirmations, + wallet: wallet, + amount: amountSending, + minimumConfirmations: minimumConfirmations, )); } } - if (fees.toUpperCase().contains("ERROR")) { //Check if the error is an //Throw the returned error @@ -399,13 +419,13 @@ abstract class LibEpiccash { var decodedFees = json.decode(fees); var feeItem = decodedFees[0]; ({ - bool strategyUseAll, - int total, - int fee, + bool strategyUseAll, + int total, + int fee, }) feeRecord = ( - strategyUseAll: feeItem['selection_strategy_is_use_all'], - total: feeItem['total'], - fee: feeItem['fee'], + strategyUseAll: feeItem['selection_strategy_is_use_all'], + total: feeItem['total'], + fee: feeItem['fee'], ); return feeRecord; } catch (e) { From 807fc677d70b21c5a3aa622396634a36e9098bfa Mon Sep 17 00:00:00 2001 From: likho Date: Fri, 29 Sep 2023 11:35:08 +0200 Subject: [PATCH 12/29] Clean up --- .../coins/epiccash/epiccash_wallet.dart | 59 ++----------------- 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index b15b2673d..4ad538e82 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -233,28 +233,12 @@ Future deleteEpicWallet({ } } -Future _initWalletWrapper( - Tuple4 data) async { - final String initWalletStr = - initWallet(data.item1, data.item2, data.item3, data.item4); - return initWalletStr; -} - +//TODO - remove and use one from abstract class Future _walletMnemonicWrapper(int throwaway) async { final String mnemonic = walletMnemonic(); return mnemonic; } -Future _recoverWrapper( - Tuple4 data) async { - return recoverWallet(data.item1, data.item2, data.item3, data.item4); -} - -Future _getChainHeightWrapper(String config) async { - final int chainHeight = getChainHeight(config); - return chainHeight; -} - class EpicCashWallet extends CoinServiceAPI with WalletCache, WalletDB, EpicCashHive { EpicCashWallet({ @@ -521,14 +505,8 @@ class EpicCashWallet extends CoinServiceAPI final wallet = await _secureStore.read(key: '${_walletId}_wallet'); EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); - ({String wallet, int index, String epicboxConfig}) data = ( - wallet: wallet!, - index: index, - epicboxConfig: epicboxConfig.toString() - ); - String? walletAddress = await epiccash.LibEpiccash.getAddressInfo( - wallet: wallet, + wallet: wallet!, index: index, epicboxConfig: epicboxConfig.toString(), ); @@ -679,13 +657,8 @@ class EpicCashWallet extends CoinServiceAPI Logging.instance.log("This index is $index", level: LogLevel.Info); EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); - ({String wallet, int index, String epicboxConfig}) data = ( - wallet: wallet!, - index: index, - epicboxConfig: epicboxConfig.toString() - ); String? walletAddress = await epiccash.LibEpiccash.getAddressInfo( - wallet: wallet, + wallet: wallet!, index: index, epicboxConfig: epicboxConfig.toString(), ); @@ -735,17 +708,6 @@ class EpicCashWallet extends CoinServiceAPI String name = _walletId; - ({ - String config, - String mnemonic, - String password, - String name, - }) walletData = ( - config: stringConfig, - mnemonic: mnemonicString, - password: password, - name: name - ); await epiccash.LibEpiccash.initializeNewWallet( config: stringConfig, mnemonic: mnemonicString, @@ -854,10 +816,9 @@ class EpicCashWallet extends CoinServiceAPI final wallet = await _secureStore.read(key: '${_walletId}_wallet'); try { final available = balance.spendable.raw.toInt(); - ({String wallet, int amount, int availableAmount}) data = - (wallet: wallet!, amount: satoshiAmount, availableAmount: available); + var transactionFees = await epiccash.LibEpiccash.getTransactionFees( - wallet: wallet, + wallet: wallet!, amount: satoshiAmount, // todo: double check minimumConfirmations: MINIMUM_CONFIRMATIONS, @@ -1163,15 +1124,7 @@ class EpicCashWallet extends CoinServiceAPI await _secureStore.write( key: '${_walletId}_epicboxConfig', value: epicboxConfig.toString()); - await compute( - _recoverWrapper, - Tuple4( - stringConfig, - password, - mnemonic, - name, - ), - ); + await epiccash.LibEpiccash.recoverWallet(config: stringConfig, password: password, mnemonic: mnemonic, name: name); await Future.wait([ epicUpdateRestoreHeight(height), From b178c306208d5f467df85e391edd76257c9e5116 Mon Sep 17 00:00:00 2001 From: likho Date: Fri, 29 Sep 2023 16:15:15 +0200 Subject: [PATCH 13/29] WIP: move send tx to use abstract class --- .../coins/epiccash/epiccash_wallet.dart | 188 +++++++++--------- lib/wallets/example/libepiccash.dart | 33 ++- 2 files changed, 120 insertions(+), 101 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 4ad538e82..32250e496 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -233,12 +233,6 @@ Future deleteEpicWallet({ } } -//TODO - remove and use one from abstract class -Future _walletMnemonicWrapper(int throwaway) async { - final String mnemonic = walletMnemonic(); - return mnemonic; -} - class EpicCashWallet extends CoinServiceAPI with WalletCache, WalletDB, EpicCashHive { EpicCashWallet({ @@ -404,88 +398,101 @@ class EpicCashWallet extends CoinServiceAPI } } - 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": txData['onChainNote'], - "amount": (txData['recipientAmt'] as Amount).raw.toInt(), - "address": txData['addresss'] as String, - }, 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(message); - } - stop(receivePort); - Logging.instance - .log('Closing txHttpSend!\n $message', level: LogLevel.Info); - } else { - ReceivePort receivePort = await getIsolate({ - "function": "createTransaction", - "wallet": wallet!, - "amount": (txData['recipientAmt'] as Amount).raw.toInt(), - "address": txData['addresss'] as String, - "secretKeyIndex": 0, - "epicboxConfig": epicboxConfig.toString(), - "minimumConfirmations": MINIMUM_CONFIRMATIONS, - "onChainNote": txData['onChainNote'], - }, 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); - } - }); + // 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": txData['onChainNote'], + // "amount": (txData['recipientAmt'] as Amount).raw.toInt(), + // "address": txData['addresss'] as String, + // }, 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(message); + // } + // stop(receivePort); + // Logging.instance + // .log('Closing txHttpSend!\n $message', level: LogLevel.Info); + // } else { + // ReceivePort receivePort = await getIsolate({ + // "function": "createTransaction", + // "wallet": wallet!, + // "amount": (txData['recipientAmt'] as Amount).raw.toInt(), + // "address": txData['addresss'] as String, + // "secretKeyIndex": 0, + // "epicboxConfig": epicboxConfig.toString(), + // "minimumConfirmations": MINIMUM_CONFIRMATIONS, + // "onChainNote": txData['onChainNote'], + // }, 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); + // } + // }); // return message; - final String sendTx = message['result'] as String; - if (sendTx.contains("Error")) { - throw BadEpicHttpAddressException(message: sendTx); - } + var transaction = await epiccash.LibEpiccash.createTransaction( + wallet: wallet!, + amount: (txData['recipientAmt'] as Amount).raw.toInt(), + address: txData['addresss'] as String, + secretKeyIndex: 0, + epicboxConfig: epicboxConfig.toString(), + minimumConfirmations: MINIMUM_CONFIRMATIONS, + note: txData['onChainNote'] as String); + // final String sendTx = message['result'] as String; + // if (sendTx.contains("Error")) { + // throw BadEpicHttpAddressException(message: sendTx); + // } + // Map txAddressInfo = {}; txAddressInfo['from'] = await currentReceivingAddress; txAddressInfo['to'] = txData['addresss'] as String; - await putSendToAddresses(sendTx, txAddressInfo); + await putSendToAddresses(transaction, txAddressInfo); - Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info); - - final decodeData = json.decode(sendTx); - - if (decodeData[0] == "transaction_failed") { - String errorMessage = decodeData[1] as String; - throw Exception("Transaction failed with error code $errorMessage"); - } else { - final txCreateResult = decodeData[0]; - // //TODO: second problem - final transaction = json.decode(txCreateResult as String); - - final tx = transaction[0]; - final txLogEntry = json.decode(tx as String); - final txLogEntryFirst = txLogEntry[0]; - final slateId = txLogEntryFirst['tx_slate_id'] as String; - return slateId!; - } + return transaction.slateId; + // + // Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info); + // + // final decodeData = json.decode(sendTx); + // + // if (decodeData[0] == "transaction_failed") { + // String errorMessage = decodeData[1] as String; + // throw Exception("Transaction failed with error code $errorMessage"); + // } else { + // final txCreateResult = decodeData[0]; + // // //TODO: second problem + // final transaction = json.decode(txCreateResult as String); + // + // final tx = transaction[0]; + // final txLogEntry = json.decode(tx as String); + // final txLogEntryFirst = txLogEntry[0]; + // final slateId = txLogEntryFirst['tx_slate_id'] as String; + // // return slateId!; + // + // } } catch (e, s) { Logging.instance.log("Error sending $e - $s", level: LogLevel.Error); rethrow; } + // return ""; } Future _getReceivingAddressForIndex( @@ -755,15 +762,10 @@ class EpicCashWallet extends CoinServiceAPI final List data = _mnemonicString.split(' '); return data; } else { - await m.protect(() async { - _mnemonicString = await compute( - _walletMnemonicWrapper, - 0, - ); - }); + _mnemonicString = epiccash.LibEpiccash.getMnemonic(); await _secureStore.write( key: '${_walletId}_mnemonic', value: _mnemonicString); - final List data = _mnemonicString!.split(' '); + final List data = _mnemonicString.split(' '); return data; } } @@ -1261,20 +1263,20 @@ class EpicCashWallet extends CoinServiceAPI } Future putSendToAddresses( - String slateMessage, Map txAddressInfo) async { + ({String slateId, String commitId}) slateData, Map txAddressInfo) async { try { var slatesToCommits = await getSlatesToCommits(); - final slate0 = jsonDecode(slateMessage); - final slate = jsonDecode(slate0[0] as String); - final part1 = jsonDecode(slate[0] as String); - final part2 = jsonDecode(slate[1] as String); - final slateId = part1[0]['tx_slate_id']; - final commitId = part2['tx']['body']['outputs'][0]['commit']; + // final slate0 = jsonDecode(slateMessage); + // final slate = jsonDecode(slate0[0] as String); + // final part1 = jsonDecode(slate[0] as String); + // final part2 = jsonDecode(slate[1] as String); + // final slateId = part1[0]['tx_slate_id']; + // final commitId = part2['tx']['body']['outputs'][0]['commit']; final from = txAddressInfo['from']; final to = txAddressInfo['to']; - slatesToCommits[slateId] = { - "commitId": commitId, + slatesToCommits[slateData.slateId] = { + "commitId": slateData.commitId, "from": from, "to": to, }; diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 8e51e0049..3dfb96cd4 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -34,7 +34,7 @@ abstract class LibEpiccash { /// // TODO: ensure the above documentation comment is correct // TODO: ensure this will always return the mnemonic. If not, this function should throw an exception - // TODO: probably remove this as we don't use it in stack wallet. We store the mnemonic separately + //Function is used in _getMnemonicList() static String getMnemonic() { try { String mnemonic = lib_epiccash.walletMnemonic(); @@ -185,7 +185,7 @@ abstract class LibEpiccash { String wallet, int amount, String address, - int secretKey, + int secretKeyIndex, String epicboxConfig, int minimumConfirmations, String note, @@ -195,7 +195,7 @@ abstract class LibEpiccash { data.wallet, data.amount, data.address, - data.secretKey, + data.secretKeyIndex, data.epicboxConfig, data.minimumConfirmations, data.note); @@ -204,25 +204,42 @@ abstract class LibEpiccash { /// /// Create an Epic transaction /// - static Future createTransaction({ + static Future<({String slateId, String commitId})> createTransaction({ required String wallet, required int amount, required String address, - required int secretKey, + required int secretKeyIndex, required String epicboxConfig, required int minimumConfirmations, required String note, }) async { try { - return await compute(_createTransactionWrapper, ( + String result = await compute(_createTransactionWrapper, ( wallet: wallet, amount: amount, address: address, - secretKey: secretKey, + secretKeyIndex: secretKeyIndex, epicboxConfig: epicboxConfig, minimumConfirmations: minimumConfirmations, note: note, )); + + if (result.toUpperCase().contains("ERROR")) { + throw Exception("Error creating transaction ${result.toString()}"); + } + + //Decode sent tx and return Slate Id + final slate0 = jsonDecode(result); + final slate = jsonDecode(slate0[0] as String); + final part1 = jsonDecode(slate[0] as String); + final part2 = jsonDecode(slate[1] as String); + + ({String slateId, String commitId}) data = ( + slateId: part1[0]['tx_slate_id'], + commitId: part2['tx']['body']['outputs'][0]['commit'], + ); + + return data; } catch (e) { throw ("Error creating epic transaction : ${e.toString()}"); } @@ -468,7 +485,7 @@ abstract class LibEpiccash { name: name, )); } catch (e) { - throw ("Error recovering wallet : ${e.toString()}"); + throw (e.toString()); } } From 8ec8c6c914a639301c29ace912cdf3280dc5f0aa Mon Sep 17 00:00:00 2001 From: likho Date: Fri, 29 Sep 2023 16:45:40 +0200 Subject: [PATCH 14/29] Update tx send to use abstract class send functions --- .../coins/epiccash/epiccash_wallet.dart | 155 +++--------------- lib/wallets/example/libepiccash.dart | 21 ++- 2 files changed, 43 insertions(+), 133 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 32250e496..a9c6a715f 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -124,51 +124,6 @@ Future executeNative(Map arguments) async { sendPort.send(result); return; } - } else if (function == "createTransaction") { - final wallet = arguments['wallet'] as String?; - final amount = arguments['amount'] as int?; - final address = arguments['address'] as String?; - final secretKeyIndex = arguments['secretKeyIndex'] as int?; - final epicboxConfig = arguments['epicboxConfig'] as String?; - final minimumConfirmations = arguments['minimumConfirmations'] as int?; - final onChainNote = arguments['onChainNote'] as String?; - - Map result = {}; - if (!(wallet == null || - amount == null || - address == null || - secretKeyIndex == null || - epicboxConfig == null || - minimumConfirmations == null)) { - var res = await createTransaction(wallet, amount, address, - secretKeyIndex, epicboxConfig, minimumConfirmations, onChainNote!); - result['result'] = res; - 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( @@ -381,12 +336,10 @@ class EpicCashWallet extends CoinServiceAPI Future confirmSend({required Map txData}) async { try { final wallet = await _secureStore.read(key: '${_walletId}_wallet'); - EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig(); // TODO determine whether it is worth sending change to a change address. - dynamic message; - + String slateId; String receiverAddress = txData['addresss'] as String; if (!receiverAddress.startsWith("http://") || @@ -398,96 +351,36 @@ class EpicCashWallet extends CoinServiceAPI } } - // 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": txData['onChainNote'], - // "amount": (txData['recipientAmt'] as Amount).raw.toInt(), - // "address": txData['addresss'] as String, - // }, 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(message); - // } - // stop(receivePort); - // Logging.instance - // .log('Closing txHttpSend!\n $message', level: LogLevel.Info); - // } else { - // ReceivePort receivePort = await getIsolate({ - // "function": "createTransaction", - // "wallet": wallet!, - // "amount": (txData['recipientAmt'] as Amount).raw.toInt(), - // "address": txData['addresss'] as String, - // "secretKeyIndex": 0, - // "epicboxConfig": epicboxConfig.toString(), - // "minimumConfirmations": MINIMUM_CONFIRMATIONS, - // "onChainNote": txData['onChainNote'], - // }, 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); - // } - // }); + ({String commitId, String slateId}) transaction; - // return message; - var transaction = await epiccash.LibEpiccash.createTransaction( - wallet: wallet!, - amount: (txData['recipientAmt'] as Amount).raw.toInt(), - address: txData['addresss'] as String, - secretKeyIndex: 0, - epicboxConfig: epicboxConfig.toString(), - minimumConfirmations: MINIMUM_CONFIRMATIONS, - note: txData['onChainNote'] as String); + if (receiverAddress.startsWith("http://") || + receiverAddress.startsWith("https://")) { + + transaction = await epiccash.LibEpiccash.txHttpSend( + wallet: wallet!, + selectionStrategyIsAll: 0, + minimumConfirmations: MINIMUM_CONFIRMATIONS, + message: txData['onChainNote'] as String, + amount: (txData['recipientAmt'] as Amount).raw.toInt(), + address: txData['addresss'] as String); + } else { + transaction = await epiccash.LibEpiccash.createTransaction( + wallet: wallet!, + amount: (txData['recipientAmt'] as Amount).raw.toInt(), + address: txData['addresss'] as String, + secretKeyIndex: 0, + epicboxConfig: epicboxConfig.toString(), + minimumConfirmations: MINIMUM_CONFIRMATIONS, + note: txData['onChainNote'] as String); + } - // final String sendTx = message['result'] as String; - // if (sendTx.contains("Error")) { - // throw BadEpicHttpAddressException(message: sendTx); - // } - // Map txAddressInfo = {}; txAddressInfo['from'] = await currentReceivingAddress; txAddressInfo['to'] = txData['addresss'] as String; await putSendToAddresses(transaction, txAddressInfo); - return transaction.slateId; - // - // Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info); - // - // final decodeData = json.decode(sendTx); - // - // if (decodeData[0] == "transaction_failed") { - // String errorMessage = decodeData[1] as String; - // throw Exception("Transaction failed with error code $errorMessage"); - // } else { - // final txCreateResult = decodeData[0]; - // // //TODO: second problem - // final transaction = json.decode(txCreateResult as String); - // - // final tx = transaction[0]; - // final txLogEntry = json.decode(tx as String); - // final txLogEntryFirst = txLogEntry[0]; - // final slateId = txLogEntryFirst['tx_slate_id'] as String; - // // return slateId!; - // - // } + slateId = transaction.slateId; + return slateId; } catch (e, s) { Logging.instance.log("Error sending $e - $s", level: LogLevel.Error); rethrow; diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 3dfb96cd4..4a152325b 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -579,7 +579,7 @@ abstract class LibEpiccash { /// /// /// - static Future txHttpSend({ + static Future<({String commitId, String slateId})> txHttpSend({ required String wallet, required int selectionStrategyIsAll, required int minimumConfirmations, @@ -588,7 +588,7 @@ abstract class LibEpiccash { required String address, }) async { try { - return await compute(_txHttpSendWrapper, ( + var result = await compute(_txHttpSendWrapper, ( wallet: wallet, selectionStrategyIsAll: selectionStrategyIsAll, minimumConfirmations: minimumConfirmations, @@ -596,6 +596,23 @@ abstract class LibEpiccash { amount: amount, address: address, )); + + if (result.toUpperCase().contains("ERROR")) { + throw Exception("Error creating transaction ${result.toString()}"); + } + + //Decode sent tx and return Slate Id + final slate0 = jsonDecode(result); + final slate = jsonDecode(slate0[0] as String); + final part1 = jsonDecode(slate[0] as String); + final part2 = jsonDecode(slate[1] as String); + + ({String slateId, String commitId}) data = ( + slateId: part1[0]['tx_slate_id'], + commitId: part2['tx']['body']['outputs'][0]['commit'], + ); + + return data; } catch (e) { throw ("Error sending tx HTTP : ${e.toString()}"); } From b8a412988f88c529840a15e065665109b18fd35d Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Fri, 29 Sep 2023 09:51:24 -0600 Subject: [PATCH 15/29] cancelTransactions and createTransaction --- .../coins/epiccash/epiccash_wallet.dart | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 32250e496..fdeb7e613 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -140,8 +140,15 @@ Future executeNative(Map arguments) async { secretKeyIndex == null || epicboxConfig == null || minimumConfirmations == null)) { - var res = await createTransaction(wallet, amount, address, - secretKeyIndex, epicboxConfig, minimumConfirmations, onChainNote!); + var res = await epiccash.LibEpiccash.createTransaction( + wallet: wallet, + amount: amount, + address: address, + secretKeyIndex: secretKeyIndex, + epicboxConfig: epicboxConfig, + minimumConfirmations: minimumConfirmations, + note: onChainNote!, + ); result['result'] = res; sendPort.send(result); return; @@ -194,14 +201,6 @@ 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(Tuple2 data) async { - // assuming this returns an empty string on success - // or an error message string on failure - return cancelTransaction(data.item1, data.item2); -} - Future deleteEpicWallet({ required String walletId, required SecureStorageInterface secureStore, @@ -358,12 +357,9 @@ class EpicCashWallet extends CoinServiceAPI ))!; final result = await m.protect(() async { - return await compute( - _cancelTransactionWrapper, - Tuple2( - wallet, - txSlateId, - ), + return await epiccash.LibEpiccash.cancelTransaction( + wallet: wallet, + transactionId: txSlateId, ); }); Logging.instance.log( @@ -1126,7 +1122,11 @@ class EpicCashWallet extends CoinServiceAPI await _secureStore.write( key: '${_walletId}_epicboxConfig', value: epicboxConfig.toString()); - await epiccash.LibEpiccash.recoverWallet(config: stringConfig, password: password, mnemonic: mnemonic, name: name); + await epiccash.LibEpiccash.recoverWallet( + config: stringConfig, + password: password, + mnemonic: mnemonic, + name: name); await Future.wait([ epicUpdateRestoreHeight(height), @@ -1262,8 +1262,8 @@ class EpicCashWallet extends CoinServiceAPI } } - Future putSendToAddresses( - ({String slateId, String commitId}) slateData, Map txAddressInfo) async { + Future putSendToAddresses(({String slateId, String commitId}) slateData, + Map txAddressInfo) async { try { var slatesToCommits = await getSlatesToCommits(); // final slate0 = jsonDecode(slateMessage); From 53b90fa01d45759b79f1df17c0fb23d78e1ff1dc Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Fri, 29 Sep 2023 10:00:46 -0600 Subject: [PATCH 16/29] another merge conflict ? --- lib/wallets/example/libepiccash.dart | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 3dfb96cd4..074413f63 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -214,7 +214,7 @@ abstract class LibEpiccash { required String note, }) async { try { - String result = await compute(_createTransactionWrapper, ( + String result = await compute(_createTransactionWrapper, ( wallet: wallet, amount: amount, address: address, @@ -579,7 +579,7 @@ abstract class LibEpiccash { /// /// /// - static Future txHttpSend({ + static Future<({String commitId, String slateId})> txHttpSend({ required String wallet, required int selectionStrategyIsAll, required int minimumConfirmations, @@ -588,7 +588,7 @@ abstract class LibEpiccash { required String address, }) async { try { - return await compute(_txHttpSendWrapper, ( + var result = await compute(_txHttpSendWrapper, ( wallet: wallet, selectionStrategyIsAll: selectionStrategyIsAll, minimumConfirmations: minimumConfirmations, @@ -596,6 +596,22 @@ abstract class LibEpiccash { amount: amount, address: address, )); + if (result.toUpperCase().contains("ERROR")) { + throw Exception("Error creating transaction ${result.toString()}"); + } + + //Decode sent tx and return Slate Id + final slate0 = jsonDecode(result); + final slate = jsonDecode(slate0[0] as String); + final part1 = jsonDecode(slate[0] as String); + final part2 = jsonDecode(slate[1] as String); + + ({String slateId, String commitId}) data = ( + slateId: part1[0]['tx_slate_id'], + commitId: part2['tx']['body']['outputs'][0]['commit'], + ); + + return data; } catch (e) { throw ("Error sending tx HTTP : ${e.toString()}"); } From c7608b0ad7b8afe2fac75cd66e2b61b3a6fc2eef Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Fri, 29 Sep 2023 15:46:33 -0600 Subject: [PATCH 17/29] format fixes and walletBalance --- .../coins/epiccash/epiccash_wallet.dart | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 5f1f4acd9..a4372cc5f 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -99,7 +99,11 @@ Future executeNative(Map arguments) async { final numberOfBlocks = arguments['numberOfBlocks'] as int?; Map result = {}; if (!(wallet == null || startHeight == null || numberOfBlocks == null)) { - var outputs = await scanOutPuts(wallet, startHeight, numberOfBlocks); + var outputs = await epiccash.LibEpiccash.scanOutputs( + wallet: wallet, + startHeight: startHeight, + numberOfBlocks: numberOfBlocks, + ); result['outputs'] = outputs; sendPort.send(result); return; @@ -119,7 +123,11 @@ Future executeNative(Map arguments) async { const int refreshFromNode = 1; Map result = {}; if (!(wallet == null)) { - var res = await getWalletInfo(wallet, refreshFromNode, 10); + var res = await epiccash.LibEpiccash.getWalletBalances( + wallet: wallet!, + refreshFromNode: refreshFromNode, + minimumConfirmations: 10, + ); result['result'] = res; sendPort.send(result); return; @@ -172,7 +180,10 @@ Future deleteEpicWallet({ return "Tried to delete non existent epic wallet file with walletId=$walletId"; } else { try { - return epiccash.LibEpiccash.deleteWallet(wallet: wallet, config: config!); + return epiccash.LibEpiccash.deleteWallet( + wallet: wallet, + config: config!, + ); } catch (e, s) { Logging.instance.log("$e\n$s", level: LogLevel.Error); return "deleteEpicWallet($walletId) failed..."; @@ -703,7 +714,6 @@ class EpicCashWallet extends CoinServiceAPI var transactionFees = await epiccash.LibEpiccash.getTransactionFees( wallet: wallet!, amount: satoshiAmount, - // todo: double check minimumConfirmations: MINIMUM_CONFIRMATIONS, available: available, ); @@ -1008,10 +1018,11 @@ class EpicCashWallet extends CoinServiceAPI key: '${_walletId}_epicboxConfig', value: epicboxConfig.toString()); await epiccash.LibEpiccash.recoverWallet( - config: stringConfig, - password: password, - mnemonic: mnemonic, - name: name); + config: stringConfig, + password: password, + mnemonic: mnemonic, + name: name, + ); await Future.wait([ epicUpdateRestoreHeight(height), From 8705340880c459c7574e00ed96e6006f1e56c199 Mon Sep 17 00:00:00 2001 From: likho Date: Tue, 3 Oct 2023 12:42:01 +0200 Subject: [PATCH 18/29] WIP: GET Transactions --- .../blockchain_data/epic_transaction.dart | 118 ++++++++++++++++++ .../coins/epiccash/epiccash_wallet.dart | 7 -- 2 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 lib/models/isar/models/blockchain_data/epic_transaction.dart diff --git a/lib/models/isar/models/blockchain_data/epic_transaction.dart b/lib/models/isar/models/blockchain_data/epic_transaction.dart new file mode 100644 index 000000000..d08b73a2d --- /dev/null +++ b/lib/models/isar/models/blockchain_data/epic_transaction.dart @@ -0,0 +1,118 @@ +/* + * This file is part of Stack Wallet. + * + * Copyright (c) 2023 Cypher Stack + * All Rights Reserved. + * The code is distributed under GPLv3 license, see LICENSE file for details. + * Generated by Cypher Stack on 2023-05-26 + * + */ + +import 'dart:convert'; +import 'dart:math'; + +import 'package:isar/isar.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/input.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/output.dart'; +import 'package:stackwallet/utilities/amount/amount.dart'; +import 'package:tuple/tuple.dart'; + +@Collection() +class EpicTransaction { + String parentKeyId; + int id; + String txSlateId; + String txType; + String creationTs; + String confirmationTs; + bool confirmed; + int numInputs; + int numOutputs; + String amountCredited; + String amountDebited; + String fee; + int? ttlCutoffHeight; // Use int? for nullable fields + List messages; + String storedTx; + String kernelExcess; + int kernelLookupMinHeight; + String? paymentProof; // Use String? for nullable fields + + EpicTransaction({ + required this.parentKeyId, + required this.id, + required this.txSlateId, + required this.txType, + required this.creationTs, + required this.confirmationTs, + required this.confirmed, + required this.numInputs, + required this.numOutputs, + required this.amountCredited, + required this.amountDebited, + required this.fee, + this.ttlCutoffHeight, + required this.messages, + required this.storedTx, + required this.kernelExcess, + required this.kernelLookupMinHeight, + this.paymentProof, + }); + + Tuple2 + + factory EpicTransaction.fromJson(Map json) { + final messagesJson = json['messages']['messages'] as List; + final messagesList = messagesJson + .map((messageJson) => MessageDto.fromJson(messageJson)) + .toList(); + + return EpicTransaction( + parentKeyId: json['parent_key_id'] as String, + id: int.parse(json['id'] as String), + txSlateId: json['tx_slate_id'] as String, + txType: json['tx_type'] as String, + creationTs: json['creation_ts'] as String, + confirmationTs: json['confirmation_ts'] as String, + confirmed: json['confirmed'] as bool, + numInputs: int.parse(json['num_inputs'] as String), + numOutputs: int.parse(json['num_outputs'] as String), + amountCredited: json['amount_credited'] as String, + amountDebited: json['amount_debited'] as String, + fee: json['fee'] as String, + ttlCutoffHeight: int.parse(json['ttl_cutoff_height'] as String), + messages: messagesList, + storedTx: json['stored_tx'] as String, + kernelExcess: json['kernel_excess'] as String, + kernelLookupMinHeight: int.parse(json['kernel_lookup_min_height'] as String), + paymentProof: json['payment_proof'] as String, + ); + } +} + +class MessageDto { + String id; + String publicKey; + String message; + String messageSig; + + MessageDto({ + required this.id, + required this.publicKey, + required this.message, + required this.messageSig, + }); + + factory MessageDto.fromJson(Map json) { + return MessageDto( + id: json['id'] as String, + publicKey: json['public_key'] as String, + message: json['message'] as String, + messageSig: json['message_sig'] as String, + ); + } +} + + + diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index a4372cc5f..fdffb0d3c 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1162,13 +1162,6 @@ class EpicCashWallet extends CoinServiceAPI Map txAddressInfo) async { try { var slatesToCommits = await getSlatesToCommits(); - // final slate0 = jsonDecode(slateMessage); - // final slate = jsonDecode(slate0[0] as String); - // final part1 = jsonDecode(slate[0] as String); - // final part2 = jsonDecode(slate[1] as String); - // final slateId = part1[0]['tx_slate_id']; - // final commitId = part2['tx']['body']['outputs'][0]['commit']; - final from = txAddressInfo['from']; final to = txAddressInfo['to']; slatesToCommits[slateData.slateId] = { From 540c8b5c5dff2c59f0588e1ec6e8d862bf69cf0a Mon Sep 17 00:00:00 2001 From: likho Date: Tue, 3 Oct 2023 16:20:44 +0200 Subject: [PATCH 19/29] WIPL:Epic transactions model --- .../blockchain_data/epic_transaction.dart | 173 ++++++++++-------- .../coins/epiccash/epiccash_wallet.dart | 3 +- 2 files changed, 94 insertions(+), 82 deletions(-) diff --git a/lib/models/isar/models/blockchain_data/epic_transaction.dart b/lib/models/isar/models/blockchain_data/epic_transaction.dart index d08b73a2d..b3147a7b3 100644 --- a/lib/models/isar/models/blockchain_data/epic_transaction.dart +++ b/lib/models/isar/models/blockchain_data/epic_transaction.dart @@ -1,48 +1,47 @@ -/* - * This file is part of Stack Wallet. - * - * Copyright (c) 2023 Cypher Stack - * All Rights Reserved. - * The code is distributed under GPLv3 license, see LICENSE file for details. - * Generated by Cypher Stack on 2023-05-26 - * - */ - -import 'dart:convert'; -import 'dart:math'; - import 'package:isar/isar.dart'; -import 'package:stackwallet/models/isar/models/blockchain_data/address.dart'; -import 'package:stackwallet/models/isar/models/blockchain_data/input.dart'; -import 'package:stackwallet/models/isar/models/blockchain_data/output.dart'; -import 'package:stackwallet/utilities/amount/amount.dart'; -import 'package:tuple/tuple.dart'; +import 'package:stackwallet/models/isar/models/isar_models.dart'; -@Collection() class EpicTransaction { - String parentKeyId; - int id; - String txSlateId; - String txType; - String creationTs; - String confirmationTs; - bool confirmed; - int numInputs; - int numOutputs; - String amountCredited; - String amountDebited; - String fee; - int? ttlCutoffHeight; // Use int? for nullable fields - List messages; - String storedTx; - String kernelExcess; - int kernelLookupMinHeight; - String? paymentProof; // Use String? for nullable fields + + Id isarId = Isar.autoIncrement; + + @Index() + late final String walletId; + + @Index() + final String parentKeyId; + + @Index(unique: true, composite: [CompositeIndex("walletId")]) + late final int id; + + final String? txSlateId; + + @enumerated + final TransactionType txType; + + final String creationTs; + final String confirmationTs; + final bool confirmed; + final int numInputs; + final int numOutputs; + final String amountCredited; + final String amountDebited; + final String? fee; + final String? ttlCutoffHeight; + final Messages? messages; + final String? storedTx; + final String? kernelExcess; + final int? kernelLookupMinHeight; + final String? paymentProof; + + @Backlink(to: "transactions") + final address = IsarLink
(); EpicTransaction({ + required this.walletId, required this.parentKeyId, required this.id, - required this.txSlateId, + this.txSlateId, required this.txType, required this.creationTs, required this.confirmationTs, @@ -51,61 +50,66 @@ class EpicTransaction { required this.numOutputs, required this.amountCredited, required this.amountDebited, - required this.fee, + this.fee, this.ttlCutoffHeight, - required this.messages, - required this.storedTx, - required this.kernelExcess, - required this.kernelLookupMinHeight, + this.messages, + this.storedTx, + this.kernelExcess, + this.kernelLookupMinHeight, this.paymentProof, }); - Tuple2 + // factory EpicTransaction.fromJson(Map json) { + // return EpicTransaction( + // parentKeyId: json['parent_key_id'] as String, + // id: json['id'] as int, + // txSlateId: json['tx_slate_id'] as String, + // txType: json['tx_type'] as TransactionType, + // creationTs: json['creation_ts'] as String, + // confirmationTs: json['confirmation_ts'] as String, + // confirmed: json['confirmed'] as bool, + // numInputs: json['num_inputs'] as int, + // numOutputs: json['num_outputs'] as int, + // amountCredited: json['amount_credited'] as String, + // amountDebited: json['amount_debited'] as String, + // fee: json['fee'] as String, + // ttlCutoffHeight: json['ttl_cutoff_height'] as String, + // messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map) : null, + // storedTx: json['stored_tx'] as String, + // kernelExcess: json['kernel_excess'] as String, + // kernelLookupMinHeight: json['kernel_lookup_min_height'] as int, + // paymentProof: json['payment_proof'] as String, + // ); + // } +} - factory EpicTransaction.fromJson(Map json) { - final messagesJson = json['messages']['messages'] as List; - final messagesList = messagesJson - .map((messageJson) => MessageDto.fromJson(messageJson)) - .toList(); +class Messages { + final List messages; - return EpicTransaction( - parentKeyId: json['parent_key_id'] as String, - id: int.parse(json['id'] as String), - txSlateId: json['tx_slate_id'] as String, - txType: json['tx_type'] as String, - creationTs: json['creation_ts'] as String, - confirmationTs: json['confirmation_ts'] as String, - confirmed: json['confirmed'] as bool, - numInputs: int.parse(json['num_inputs'] as String), - numOutputs: int.parse(json['num_outputs'] as String), - amountCredited: json['amount_credited'] as String, - amountDebited: json['amount_debited'] as String, - fee: json['fee'] as String, - ttlCutoffHeight: int.parse(json['ttl_cutoff_height'] as String), - messages: messagesList, - storedTx: json['stored_tx'] as String, - kernelExcess: json['kernel_excess'] as String, - kernelLookupMinHeight: int.parse(json['kernel_lookup_min_height'] as String), - paymentProof: json['payment_proof'] as String, - ); + Messages({required this.messages}); + + factory Messages.fromJson(Map json) { + final messageList = json['messages'] as List; + final messages = messageList.map((message) => Message.fromJson(message as Map)).toList(); + return Messages(messages: messages); } } -class MessageDto { - String id; - String publicKey; - String message; - String messageSig; +class Message { + final String id; + final String publicKey; + final String? message; + final String? messageSig; - MessageDto({ + Message({ required this.id, required this.publicKey, - required this.message, - required this.messageSig, + this.message, + this.messageSig, }); - factory MessageDto.fromJson(Map json) { - return MessageDto( + factory Message.fromJson(Map json) { + return Message( id: json['id'] as String, publicKey: json['public_key'] as String, message: json['message'] as String, @@ -114,5 +118,12 @@ class MessageDto { } } - - +// Used in Isar db and stored there as int indexes so adding/removing values +// in this definition should be done extremely carefully in production +enum TransactionType { + // TODO: add more types before prod release? + outgoing, + incoming, + sentToSelf, // should we keep this? + unknown; +} diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index fdffb0d3c..2beba6f78 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1408,6 +1408,8 @@ class EpicCashWallet extends CoinServiceAPI }); // return message; final String transactions = message['result'] as String; + + print("RETURNED TRANSACTIONS IS $transactions"); final jsonTransactions = json.decode(transactions) as List; final List> txnsData = @@ -1472,7 +1474,6 @@ class EpicCashWallet extends CoinServiceAPI isLelantus: false, slateId: slateId, nonce: null, - // otherData: tx["id"].toString(), otherData: tx['onChainNote'].toString(), inputs: [], outputs: [], From e28c7f501911c03ac2d885f852addff030ff098e Mon Sep 17 00:00:00 2001 From: Likho Date: Tue, 3 Oct 2023 16:35:13 +0200 Subject: [PATCH 20/29] WIP: Epic transaction data class --- .../blockchain_data/epic_transaction.dart | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/lib/models/isar/models/blockchain_data/epic_transaction.dart b/lib/models/isar/models/blockchain_data/epic_transaction.dart index b3147a7b3..9640ff49f 100644 --- a/lib/models/isar/models/blockchain_data/epic_transaction.dart +++ b/lib/models/isar/models/blockchain_data/epic_transaction.dart @@ -3,8 +3,6 @@ import 'package:stackwallet/models/isar/models/isar_models.dart'; class EpicTransaction { - Id isarId = Isar.autoIncrement; - @Index() late final String walletId; @@ -38,7 +36,6 @@ class EpicTransaction { final address = IsarLink
(); EpicTransaction({ - required this.walletId, required this.parentKeyId, required this.id, this.txSlateId, @@ -59,28 +56,28 @@ class EpicTransaction { this.paymentProof, }); - // factory EpicTransaction.fromJson(Map json) { - // return EpicTransaction( - // parentKeyId: json['parent_key_id'] as String, - // id: json['id'] as int, - // txSlateId: json['tx_slate_id'] as String, - // txType: json['tx_type'] as TransactionType, - // creationTs: json['creation_ts'] as String, - // confirmationTs: json['confirmation_ts'] as String, - // confirmed: json['confirmed'] as bool, - // numInputs: json['num_inputs'] as int, - // numOutputs: json['num_outputs'] as int, - // amountCredited: json['amount_credited'] as String, - // amountDebited: json['amount_debited'] as String, - // fee: json['fee'] as String, - // ttlCutoffHeight: json['ttl_cutoff_height'] as String, - // messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map) : null, - // storedTx: json['stored_tx'] as String, - // kernelExcess: json['kernel_excess'] as String, - // kernelLookupMinHeight: json['kernel_lookup_min_height'] as int, - // paymentProof: json['payment_proof'] as String, - // ); - // } + factory EpicTransaction.fromJson(Map json) { + return EpicTransaction( + parentKeyId: json['parent_key_id'] as String, + id: json['id'] as int, + txSlateId: json['tx_slate_id'] as String, + txType: json['tx_type'] as TransactionType, + creationTs: json['creation_ts'] as String, + confirmationTs: json['confirmation_ts'] as String, + confirmed: json['confirmed'] as bool, + numInputs: json['num_inputs'] as int, + numOutputs: json['num_outputs'] as int, + amountCredited: json['amount_credited'] as String, + amountDebited: json['amount_debited'] as String, + fee: json['fee'] as String, + ttlCutoffHeight: json['ttl_cutoff_height'] as String, + messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map) : null, + storedTx: json['stored_tx'] as String, + kernelExcess: json['kernel_excess'] as String, + kernelLookupMinHeight: json['kernel_lookup_min_height'] as int, + paymentProof: json['payment_proof'] as String, + ); + } } class Messages { @@ -118,10 +115,9 @@ class Message { } } -// Used in Isar db and stored there as int indexes so adding/removing values -// in this definition should be done extremely carefully in production -enum TransactionType { - // TODO: add more types before prod release? + +enum EpicTransactionType { + //Use Epic transaction type here outgoing, incoming, sentToSelf, // should we keep this? From 684388c6f977e8ab9e41254f7d7f47b11fee79e3 Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Tue, 3 Oct 2023 19:01:43 -0600 Subject: [PATCH 21/29] WIP: scanOutputs --- lib/services/coins/epiccash/epiccash_wallet.dart | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index a4372cc5f..7b101b4b5 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -284,6 +284,20 @@ class EpicCashWallet extends CoinServiceAPI return ""; } + Future scanOutPuts() async { + final String wallet = + (await _secureStore.read(key: '${_walletId}_wallet'))!; + final int lastScannedBlock = + epicGetLastScannedBlock() ?? await getRestoreHeight(); + final int scanChunkSize = 10000; + + return await epiccash.LibEpiccash.scanOutputs( + wallet: wallet, + startHeight: lastScannedBlock, + numberOfBlocks: scanChunkSize, + ); + } + Future< ({ double awaitingFinalization, From d2ed34a2d02310ed644a96cf4c157f5a3c60d20d Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Tue, 3 Oct 2023 19:02:48 -0600 Subject: [PATCH 22/29] WIP: startScans --- .../coins/epiccash/epiccash_wallet.dart | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 7b101b4b5..e920baf66 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -894,6 +894,107 @@ class EpicCashWallet extends CoinServiceAPI // TODO: refresh anything that needs to be refreshed/updated due to epicbox info changed } +// Future _startScans() async { +// try { +// //First stop the current listener +// if (ListenerManager.pointer != null) { +// Logging.instance +// .log("LISTENER HANDLER IS NOT NULL ....", level: LogLevel.Info); +// Logging.instance +// .log("STOPPING ANY WALLET LISTENER ....", level: LogLevel.Info); +// epicboxListenerStop(ListenerManager.pointer!); +// } +// final wallet = await _secureStore.read(key: '${_walletId}_wallet'); +// +// // max number of blocks to scan per loop iteration +// const scanChunkSize = 10000; +// +// // force firing of scan progress event +// await getSyncPercent; +// +// // fetch current chain height and last scanned block (should be the +// // restore height if full rescan or a wallet restore) +// int chainHeight = await this.chainHeight; +// int lastScannedBlock = +// epicGetLastScannedBlock() ?? await getRestoreHeight(); +// +// // loop while scanning in chain in chunks (of blocks?) +// while (lastScannedBlock < chainHeight) { +// Logging.instance.log( +// "chainHeight: $chainHeight, lastScannedBlock: $lastScannedBlock", +// level: LogLevel.Info, +// ); +// +// // final int nextScannedBlock = await m.protect(() async { +// final result = await m.protect(() async { +// return await epiccash.LibEpiccash.scanOutputs( +// wallet: wallet!, +// startHeight: lastScannedBlock, +// numberOfBlocks: scanChunkSize, +// ); +// +// // // ReceivePort? receivePort; +// // try { +// // // receivePort = await getIsolate({ +// // // "function": "scanOutPuts", +// // // "wallet": wallet!, +// // // "startHeight": lastScannedBlock, +// // // "numberOfBlocks": scanChunkSize, +// // // }, name: walletName); +// // +// // // get response +// // final message = await receivePort.first; +// // +// // // check for error message +// // if (message is String) { +// // throw Exception("scanOutPuts isolate failed: $message"); +// // } +// // +// // // attempt to grab next scanned block number +// // final nextScanned = int.tryParse(message['outputs'] as String); +// // if (nextScanned == null) { +// // throw Exception( +// // "scanOutPuts failed to parse next scanned block number from: $message", +// // ); +// // } +// // +// // return nextScanned; +// // } catch (_) { +// // rethrow; +// // } finally { +// // if (receivePort != null) { +// // // kill isolate +// // stop(receivePort); +// // } +// // } +// }); +// +// // update local cache +// await epicUpdateLastScannedBlock(result as int); +// +// // force firing of scan progress event +// await getSyncPercent; +// +// // update while loop condition variables +// chainHeight = await this.chainHeight; +// lastScannedBlock = nextScannedBlock; +// } +// +// Logging.instance.log( +// "_startScans successfully at the tip", +// level: LogLevel.Info, +// ); +// //Once scanner completes restart listener +// await listenToEpicbox(); +// } catch (e, s) { +// Logging.instance.log( +// "_startScans failed: $e\n$s", +// level: LogLevel.Error, +// ); +// rethrow; +// } +// } + Future _startScans() async { try { //First stop the current listener From 3b4de2b2d5a9c71b09b4bf6908f01547cc84a183 Mon Sep 17 00:00:00 2001 From: likho Date: Wed, 4 Oct 2023 09:53:05 +0200 Subject: [PATCH 23/29] Add EpicTransaction DTO for parsing transactions, clean out mutex stuff for calls to the abstract class --- .../blockchain_data/epic_transaction.dart | 80 ++++++------- .../coins/epiccash/epiccash_wallet.dart | 108 ++++++------------ lib/wallets/example/libepiccash.dart | 24 +++- 3 files changed, 90 insertions(+), 122 deletions(-) diff --git a/lib/models/isar/models/blockchain_data/epic_transaction.dart b/lib/models/isar/models/blockchain_data/epic_transaction.dart index 9640ff49f..251c89705 100644 --- a/lib/models/isar/models/blockchain_data/epic_transaction.dart +++ b/lib/models/isar/models/blockchain_data/epic_transaction.dart @@ -1,22 +1,18 @@ -import 'package:isar/isar.dart'; -import 'package:stackwallet/models/isar/models/isar_models.dart'; +/* + * This file is part of Stack Wallet. + * + * Copyright (c) 2023 Cypher Stack + * All Rights Reserved. + * The code is distributed under GPLv3 license, see LICENSE file for details. + * Generated by Cypher Stack on 2023-10-03 + * + */ class EpicTransaction { - - @Index() - late final String walletId; - - @Index() final String parentKeyId; - - @Index(unique: true, composite: [CompositeIndex("walletId")]) - late final int id; - + final int id; final String? txSlateId; - - @enumerated - final TransactionType txType; - + final EpicTransactionType txType; final String creationTs; final String confirmationTs; final bool confirmed; @@ -32,9 +28,6 @@ class EpicTransaction { final int? kernelLookupMinHeight; final String? paymentProof; - @Backlink(to: "transactions") - final address = IsarLink
(); - EpicTransaction({ required this.parentKeyId, required this.id, @@ -56,26 +49,27 @@ class EpicTransaction { this.paymentProof, }); - factory EpicTransaction.fromJson(Map json) { + factory EpicTransaction.fromJson(dynamic json) { + // print("THIS JSON IS $json") return EpicTransaction( parentKeyId: json['parent_key_id'] as String, - id: json['id'] as int, - txSlateId: json['tx_slate_id'] as String, - txType: json['tx_type'] as TransactionType, - creationTs: json['creation_ts'] as String, - confirmationTs: json['confirmation_ts'] as String, - confirmed: json['confirmed'] as bool, - numInputs: json['num_inputs'] as int, - numOutputs: json['num_outputs'] as int, - amountCredited: json['amount_credited'] as String, - amountDebited: json['amount_debited'] as String, - fee: json['fee'] as String, - ttlCutoffHeight: json['ttl_cutoff_height'] as String, + id: int.parse(json!['id'].toString()), + txSlateId: json['tx_slate_id'].toString(), + txType: EpicTransactionType.values.byName(json['tx_type'] as String), + creationTs: json['creation_ts'].toString(), + confirmationTs: json['confirmation_ts'].toString(), + confirmed: bool.parse(json['confirmed'].toString()), + numInputs: int.parse(json['num_inputs'].toString()), + numOutputs: int.parse(json['num_outputs'].toString()), + amountCredited: json['amount_credited'].toString(), + amountDebited: json['amount_debited'].toString(), + fee: json['fee'].toString(), + ttlCutoffHeight: json['ttl_cutoff_height'].toString(), messages: json['messages'] != null ? Messages.fromJson(json['messages'] as Map) : null, - storedTx: json['stored_tx'] as String, - kernelExcess: json['kernel_excess'] as String, - kernelLookupMinHeight: json['kernel_lookup_min_height'] as int, - paymentProof: json['payment_proof'] as String, + storedTx: json['stored_tx'].toString(), + kernelExcess: json['kernel_excess'].toString(), + kernelLookupMinHeight: json['kernel_lookup_min_height'] == null? null : int.parse(json['kernel_lookup_min_height'].toString()), + paymentProof: json['payment_proof'].toString(), ); } } @@ -107,10 +101,10 @@ class Message { factory Message.fromJson(Map json) { return Message( - id: json['id'] as String, - publicKey: json['public_key'] as String, - message: json['message'] as String, - messageSig: json['message_sig'] as String, + id: json['id'].toString(), + publicKey: json['public_key'].toString(), + message: json['message'].toString(), + messageSig: json['message_sig'].toString(), ); } } @@ -118,8 +112,8 @@ class Message { enum EpicTransactionType { //Use Epic transaction type here - outgoing, - incoming, - sentToSelf, // should we keep this? - unknown; + TxReceived, + TxReceivedCancelled, + TxSent, + TxSentCancelled, // should we keep this? } diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 2beba6f78..efb179deb 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -23,6 +23,7 @@ import 'package:stack_wallet_backup/generate_password.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/epicbox_config_model.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/node_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; @@ -108,16 +109,6 @@ Future executeNative(Map arguments) async { sendPort.send(result); return; } - } else if (function == "getTransactions") { - final wallet = arguments['wallet'] as String?; - final refreshFromNode = arguments['refreshFromNode'] as int?; - Map result = {}; - if (!(wallet == null || refreshFromNode == null)) { - var res = await getTransactions(wallet, refreshFromNode); - result['result'] = res; - sendPort.send(result); - return; - } } else if (function == "startSync") { final wallet = arguments['wallet'] as String?; const int refreshFromNode = 1; @@ -315,12 +306,10 @@ class EpicCashWallet extends CoinServiceAPI key: '${_walletId}_wallet', ))!; - final result = await m.protect(() async { - return await epiccash.LibEpiccash.cancelTransaction( - wallet: wallet, - transactionId: txSlateId, - ); - }); + final result = await epiccash.LibEpiccash.cancelTransaction( + wallet: wallet, + transactionId: txSlateId, + ); Logging.instance.log( "cancel $txSlateId result: $result", level: LogLevel.Info, @@ -1062,14 +1051,11 @@ class EpicCashWallet extends CoinServiceAPI Future get chainHeight async { try { final config = await getRealConfig(); - int? latestHeight; - await m.protect(() async { - latestHeight = - await epiccash.LibEpiccash.getChainHeight(config: config); - }); + int? latestHeight = + await epiccash.LibEpiccash.getChainHeight(config: config); - await updateCachedChainHeight(latestHeight!); - if (latestHeight! > storedChainHeight) { + await updateCachedChainHeight(latestHeight); + if (latestHeight > storedChainHeight) { GlobalEventBus.instance.fire( UpdatedInBackgroundEvent( "Updated current chain height in $walletId $walletName!", @@ -1077,7 +1063,7 @@ class EpicCashWallet extends CoinServiceAPI ), ); } - return latestHeight!; + return latestHeight; } catch (e, s) { Logging.instance.log("Exception caught in chainHeight: $e\n$s", level: LogLevel.Error); @@ -1383,80 +1369,56 @@ class EpicCashWallet extends CoinServiceAPI bool get isConnected => _isConnected; Future _refreshTransactions() async { - // final currentChainHeight = await chainHeight; + final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 1; - dynamic message; - await m.protect(() async { - ReceivePort receivePort = await getIsolate({ - "function": "getTransactions", - "wallet": wallet!, - "refreshFromNode": refreshFromNode, - }, 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("getTransactions isolate failed"); - } - stop(receivePort); - Logging.instance - .log('Closing getTransactions!\n $message', level: LogLevel.Info); - }); - // return message; - final String transactions = message['result'] as String; - - print("RETURNED TRANSACTIONS IS $transactions"); - final jsonTransactions = json.decode(transactions) as List; + var transactions = await epiccash.LibEpiccash.getTransactions(wallet: wallet!, refreshFromNode: refreshFromNode); final List> txnsData = []; final slatesToCommits = await getSlatesToCommits(); - for (var tx in jsonTransactions) { + for (var tx in transactions) { Logging.instance.log("tx: $tx", level: LogLevel.Info); // // TODO: does "confirmed" mean finalized? If so please remove this todo - final isConfirmed = tx["confirmed"] as bool; + final isConfirmed = tx.confirmed; int amt = 0; - if (tx["tx_type"] == "TxReceived" || - tx["tx_type"] == "TxReceivedCancelled") { - amt = int.parse(tx['amount_credited'] as String); + if (tx.txType == EpicTransactionType.TxReceived || + tx.txType == EpicTransactionType.TxReceivedCancelled) { + amt = int.parse(tx.amountCredited); } else { - int debit = int.parse(tx['amount_debited'] as String); - int credit = int.parse(tx['amount_credited'] as String); - int fee = int.parse((tx['fee'] ?? "0") as String); + int debit = int.parse(tx.amountDebited); + int credit = int.parse(tx.amountCredited); + int fee = int.parse((tx.fee ?? "0")); amt = debit - credit - fee; } - DateTime dt = DateTime.parse(tx["creation_ts"] as String); + DateTime dt = DateTime.parse(tx.creationTs); - String? slateId = tx['tx_slate_id'] as String?; + String? slateId = tx.txSlateId; String address = slatesToCommits[slateId] - ?[tx["tx_type"] == "TxReceived" ? "from" : "to"] as String? ?? + ?[tx.txType == EpicTransactionType.TxReceived ? "from" : "to"] as String? ?? ""; String? commitId = slatesToCommits[slateId]?['commitId'] as String?; - tx['numberOfMessages'] = tx['messages']?['messages']?.length; - tx['onChainNote'] = tx['messages']?['messages']?[0]?['message']; + int? numberOfMessages = tx.messages?.messages.length; + String? onChainNote = tx.messages?.messages[0].message; int? height; if (isConfirmed) { - height = tx["kernel_lookup_min_height"] as int? ?? 1; + height = tx.kernelLookupMinHeight ?? 1; } else { height = null; } - final isIncoming = (tx["tx_type"] == "TxReceived" || - tx["tx_type"] == "TxReceivedCancelled"); - + final isIncoming = (tx.txType == EpicTransactionType.TxReceived || + tx.txType == EpicTransactionType.TxReceivedCancelled); final txn = isar_models.Transaction( walletId: walletId, - txid: commitId ?? tx["id"].toString(), + txid: commitId ?? tx.id.toString(), timestamp: (dt.millisecondsSinceEpoch ~/ 1000), type: isIncoming ? isar_models.TransactionType.incoming @@ -1467,19 +1429,17 @@ class EpicCashWallet extends CoinServiceAPI rawValue: BigInt.from(amt), fractionDigits: coin.decimals, ).toJsonString(), - fee: (tx["fee"] == null) ? 0 : int.parse(tx["fee"] as String), + fee: (tx.fee == "null") ? 0 : int.parse(tx.fee!), height: height, - isCancelled: tx["tx_type"] == "TxSentCancelled" || - tx["tx_type"] == "TxReceivedCancelled", + isCancelled: tx.txType == EpicTransactionType.TxSentCancelled || + tx.txType == EpicTransactionType.TxReceivedCancelled, isLelantus: false, slateId: slateId, nonce: null, - otherData: tx['onChainNote'].toString(), + otherData: onChainNote, inputs: [], outputs: [], - numberOfMessages: ((tx["numberOfMessages"] == null) - ? 0 - : tx["numberOfMessages"]) as int, + numberOfMessages: numberOfMessages, ); // txn.address = diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index 074413f63..f6cb1d913 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -4,6 +4,7 @@ import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_libepiccash/epic_cash.dart' as lib_epiccash; import 'package:mutex/mutex.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/epic_transaction.dart'; /// /// Wrapped up calls to flutter_libepiccash. @@ -263,17 +264,30 @@ abstract class LibEpiccash { /// /// /// - static Future getTransaction({ + static Future> getTransactions({ required String wallet, required int refreshFromNode, }) async { try { - return await compute(_getTransactionsWrapper, ( - wallet: wallet, - refreshFromNode: refreshFromNode, + var result = await compute(_getTransactionsWrapper, ( + wallet: wallet, + refreshFromNode: refreshFromNode, )); + + if (result.toUpperCase().contains("ERROR")) { + throw Exception("Error getting epic transactions ${result.toString()}"); + } + //Parse the returned data as an EpicTransaction + List finalResult = []; + var jsonResult = json.decode(result) as List; + for (var tx in jsonResult) { + EpicTransaction itemTx = EpicTransaction.fromJson(tx); + finalResult.add(itemTx); + } + + return finalResult; } catch (e) { - throw ("Error getting epic transaction : ${e.toString()}"); + throw ("Error getting epic transactions : ${e.toString()}"); } } From 9746e789a0980e4c63f07392f0329716e75dc8be Mon Sep 17 00:00:00 2001 From: likho Date: Wed, 4 Oct 2023 09:59:53 +0200 Subject: [PATCH 24/29] add note --- lib/services/coins/epiccash/epiccash_wallet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 98e8e8986..07cbcb236 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1507,7 +1507,7 @@ class EpicCashWallet extends CoinServiceAPI } else { int debit = int.parse(tx.amountDebited); int credit = int.parse(tx.amountCredited); - int fee = int.parse((tx.fee ?? "0")); + int fee = int.parse((tx.fee ?? "0")); //TODO -double check this amt = debit - credit - fee; } From c08bdd3c087dc4ac06e4df6306cb0fb537c89c4d Mon Sep 17 00:00:00 2001 From: likho Date: Wed, 4 Oct 2023 15:31:35 +0200 Subject: [PATCH 25/29] Remove startSync isolate --- .../coins/epiccash/epiccash_wallet.dart | 40 +++---------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 07cbcb236..c162a1420 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -109,20 +109,6 @@ Future executeNative(Map arguments) async { sendPort.send(result); return; } - } else if (function == "startSync") { - final wallet = arguments['wallet'] as String?; - const int refreshFromNode = 1; - Map result = {}; - if (!(wallet == null)) { - var res = await epiccash.LibEpiccash.getWalletBalances( - wallet: wallet!, - refreshFromNode: refreshFromNode, - minimumConfirmations: 10, - ); - result['result'] = res; - sendPort.send(result); - return; - } } Logging.instance.log( @@ -247,28 +233,14 @@ class EpicCashWallet extends CoinServiceAPI Future startSync() async { Logging.instance.log("request start sync", level: LogLevel.Info); final wallet = await _secureStore.read(key: '${_walletId}_wallet'); - + const int refreshFromNode = 1; if (!syncMutex.isLocked) { - await syncMutex.protect(() async { - Logging.instance.log("sync started", level: LogLevel.Info); - ReceivePort receivePort = await getIsolate({ - "function": "startSync", - "wallet": wallet!, - }, name: walletName); - this.receivePort = receivePort; - var message = await receivePort.first; - if (message is String) { - Logging.instance - .log("this is a string $message", level: LogLevel.Error); - stop(receivePort); - throw Exception("startSync isolate failed"); - } - stop(receivePort); - Logging.instance - .log('Closing startSync!\n $message', level: LogLevel.Info); - Logging.instance.log("sync ended", level: LogLevel.Info); - }); + await epiccash.LibEpiccash.getWalletBalances( + wallet: wallet!, + refreshFromNode: refreshFromNode, + minimumConfirmations: 10, + ); } else { Logging.instance.log("request start sync denied", level: LogLevel.Info); } From 5c15d58c2ee4be39cea29af20fd1b133f55cd690 Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Wed, 4 Oct 2023 08:50:44 -0600 Subject: [PATCH 26/29] remove scanOutput function --- lib/services/coins/epiccash/epiccash_wallet.dart | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index bae1ec80e..c2a43d175 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -284,20 +284,6 @@ class EpicCashWallet extends CoinServiceAPI return ""; } - Future scanOutPuts() async { - final String wallet = - (await _secureStore.read(key: '${_walletId}_wallet'))!; - final int lastScannedBlock = - epicGetLastScannedBlock() ?? await getRestoreHeight(); - final int scanChunkSize = 10000; - - return await epiccash.LibEpiccash.scanOutputs( - wallet: wallet, - startHeight: lastScannedBlock, - numberOfBlocks: scanChunkSize, - ); - } - Future< ({ double awaitingFinalization, From db6110997a3249c2ff6bf21e4f617a3165a544c4 Mon Sep 17 00:00:00 2001 From: ryleedavis Date: Wed, 4 Oct 2023 17:03:46 -0600 Subject: [PATCH 27/29] remove scanOutput isolate --- .../coins/epiccash/epiccash_wallet.dart | 169 ++---------------- 1 file changed, 10 insertions(+), 159 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index 1af0d7a6d..698a1ddc0 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -94,23 +94,6 @@ Future executeNative(Map arguments) async { final SendPort sendPort = arguments['sendPort'] as SendPort; final function = arguments['function'] as String; try { - if (function == "scanOutPuts") { - final wallet = arguments['wallet'] as String?; - final startHeight = arguments['startHeight'] as int?; - final numberOfBlocks = arguments['numberOfBlocks'] as int?; - Map result = {}; - if (!(wallet == null || startHeight == null || numberOfBlocks == null)) { - var outputs = await epiccash.LibEpiccash.scanOutputs( - wallet: wallet, - startHeight: startHeight, - numberOfBlocks: numberOfBlocks, - ); - result['outputs'] = outputs; - sendPort.send(result); - return; - } - } - Logging.instance.log( "Error Arguments for $function not formatted correctly", level: LogLevel.Fatal); @@ -235,7 +218,6 @@ class EpicCashWallet extends CoinServiceAPI final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const int refreshFromNode = 1; if (!syncMutex.isLocked) { - await epiccash.LibEpiccash.getWalletBalances( wallet: wallet!, refreshFromNode: refreshFromNode, @@ -841,107 +823,6 @@ class EpicCashWallet extends CoinServiceAPI // TODO: refresh anything that needs to be refreshed/updated due to epicbox info changed } -// Future _startScans() async { -// try { -// //First stop the current listener -// if (ListenerManager.pointer != null) { -// Logging.instance -// .log("LISTENER HANDLER IS NOT NULL ....", level: LogLevel.Info); -// Logging.instance -// .log("STOPPING ANY WALLET LISTENER ....", level: LogLevel.Info); -// epicboxListenerStop(ListenerManager.pointer!); -// } -// final wallet = await _secureStore.read(key: '${_walletId}_wallet'); -// -// // max number of blocks to scan per loop iteration -// const scanChunkSize = 10000; -// -// // force firing of scan progress event -// await getSyncPercent; -// -// // fetch current chain height and last scanned block (should be the -// // restore height if full rescan or a wallet restore) -// int chainHeight = await this.chainHeight; -// int lastScannedBlock = -// epicGetLastScannedBlock() ?? await getRestoreHeight(); -// -// // loop while scanning in chain in chunks (of blocks?) -// while (lastScannedBlock < chainHeight) { -// Logging.instance.log( -// "chainHeight: $chainHeight, lastScannedBlock: $lastScannedBlock", -// level: LogLevel.Info, -// ); -// -// // final int nextScannedBlock = await m.protect(() async { -// final result = await m.protect(() async { -// return await epiccash.LibEpiccash.scanOutputs( -// wallet: wallet!, -// startHeight: lastScannedBlock, -// numberOfBlocks: scanChunkSize, -// ); -// -// // // ReceivePort? receivePort; -// // try { -// // // receivePort = await getIsolate({ -// // // "function": "scanOutPuts", -// // // "wallet": wallet!, -// // // "startHeight": lastScannedBlock, -// // // "numberOfBlocks": scanChunkSize, -// // // }, name: walletName); -// // -// // // get response -// // final message = await receivePort.first; -// // -// // // check for error message -// // if (message is String) { -// // throw Exception("scanOutPuts isolate failed: $message"); -// // } -// // -// // // attempt to grab next scanned block number -// // final nextScanned = int.tryParse(message['outputs'] as String); -// // if (nextScanned == null) { -// // throw Exception( -// // "scanOutPuts failed to parse next scanned block number from: $message", -// // ); -// // } -// // -// // return nextScanned; -// // } catch (_) { -// // rethrow; -// // } finally { -// // if (receivePort != null) { -// // // kill isolate -// // stop(receivePort); -// // } -// // } -// }); -// -// // update local cache -// await epicUpdateLastScannedBlock(result as int); -// -// // force firing of scan progress event -// await getSyncPercent; -// -// // update while loop condition variables -// chainHeight = await this.chainHeight; -// lastScannedBlock = nextScannedBlock; -// } -// -// Logging.instance.log( -// "_startScans successfully at the tip", -// level: LogLevel.Info, -// ); -// //Once scanner completes restart listener -// await listenToEpicbox(); -// } catch (e, s) { -// Logging.instance.log( -// "_startScans failed: $e\n$s", -// level: LogLevel.Error, -// ); -// rethrow; -// } -// } - Future _startScans() async { try { //First stop the current listener @@ -973,42 +854,11 @@ class EpicCashWallet extends CoinServiceAPI level: LogLevel.Info, ); - final int nextScannedBlock = await m.protect(() async { - ReceivePort? receivePort; - try { - receivePort = await getIsolate({ - "function": "scanOutPuts", - "wallet": wallet!, - "startHeight": lastScannedBlock, - "numberOfBlocks": scanChunkSize, - }, name: walletName); - - // get response - final message = await receivePort.first; - - // check for error message - if (message is String) { - throw Exception("scanOutPuts isolate failed: $message"); - } - - // attempt to grab next scanned block number - final nextScanned = int.tryParse(message['outputs'] as String); - if (nextScanned == null) { - throw Exception( - "scanOutPuts failed to parse next scanned block number from: $message", - ); - } - - return nextScanned; - } catch (_) { - rethrow; - } finally { - if (receivePort != null) { - // kill isolate - stop(receivePort); - } - } - }); + int nextScannedBlock = int.parse(await epiccash.LibEpiccash.scanOutputs( + wallet: wallet!, + startHeight: lastScannedBlock, + numberOfBlocks: scanChunkSize, + )); // update local cache await epicUpdateLastScannedBlock(nextScannedBlock); @@ -1125,7 +975,7 @@ class EpicCashWallet extends CoinServiceAPI try { final config = await getRealConfig(); int? latestHeight = - await epiccash.LibEpiccash.getChainHeight(config: config); + await epiccash.LibEpiccash.getChainHeight(config: config); await updateCachedChainHeight(latestHeight); if (latestHeight > storedChainHeight) { @@ -1442,11 +1292,11 @@ class EpicCashWallet extends CoinServiceAPI bool get isConnected => _isConnected; Future _refreshTransactions() async { - final wallet = await _secureStore.read(key: '${_walletId}_wallet'); const refreshFromNode = 1; - var transactions = await epiccash.LibEpiccash.getTransactions(wallet: wallet!, refreshFromNode: refreshFromNode); + var transactions = await epiccash.LibEpiccash.getTransactions( + wallet: wallet!, refreshFromNode: refreshFromNode); final List> txnsData = []; @@ -1473,7 +1323,8 @@ class EpicCashWallet extends CoinServiceAPI String? slateId = tx.txSlateId; String address = slatesToCommits[slateId] - ?[tx.txType == EpicTransactionType.TxReceived ? "from" : "to"] as String? ?? + ?[tx.txType == EpicTransactionType.TxReceived ? "from" : "to"] + as String? ?? ""; String? commitId = slatesToCommits[slateId]?['commitId'] as String?; int? numberOfMessages = tx.messages?.messages.length; From e18c06fbcd3af550903de430380777ea05fe25ec Mon Sep 17 00:00:00 2001 From: likho Date: Fri, 6 Oct 2023 11:55:24 +0200 Subject: [PATCH 28/29] Fix missing receiving address for incoming transactions --- lib/services/coins/epiccash/epiccash_wallet.dart | 8 +++++--- lib/wallets/example/libepiccash.dart | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index c162a1420..129fd2f95 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -1485,7 +1485,7 @@ class EpicCashWallet extends CoinServiceAPI DateTime dt = DateTime.parse(tx.creationTs); - String? slateId = tx.txSlateId; + String? slateId = tx.txSlateId == "null" ? null : tx.txSlateId; String address = slatesToCommits[slateId] ?[tx.txType == EpicTransactionType.TxReceived ? "from" : "to"] as String? ?? ""; @@ -1537,11 +1537,13 @@ class EpicCashWallet extends CoinServiceAPI .valueEqualTo(address) .findFirst(); - if (transactionAddress == null) { + if (transactionAddress!.value.isEmpty) { if (isIncoming) { + //Use current receiving address as address + String receivingAddress = await currentReceivingAddress; transactionAddress = isar_models.Address( walletId: walletId, - value: address, + value: receivingAddress, publicKey: [], derivationIndex: 0, derivationPath: null, diff --git a/lib/wallets/example/libepiccash.dart b/lib/wallets/example/libepiccash.dart index f6cb1d913..28619e94a 100644 --- a/lib/wallets/example/libepiccash.dart +++ b/lib/wallets/example/libepiccash.dart @@ -277,14 +277,15 @@ abstract class LibEpiccash { if (result.toUpperCase().contains("ERROR")) { throw Exception("Error getting epic transactions ${result.toString()}"); } + //Parse the returned data as an EpicTransaction List finalResult = []; var jsonResult = json.decode(result) as List; + for (var tx in jsonResult) { EpicTransaction itemTx = EpicTransaction.fromJson(tx); finalResult.add(itemTx); } - return finalResult; } catch (e) { throw ("Error getting epic transactions : ${e.toString()}"); From 9d6c04f68fcffbace2e66ed1f2498a4cee93533f Mon Sep 17 00:00:00 2001 From: likho Date: Fri, 6 Oct 2023 12:04:24 +0200 Subject: [PATCH 29/29] Remove isolate stuff --- .../coins/epiccash/epiccash_wallet.dart | 60 ------------------- 1 file changed, 60 deletions(-) diff --git a/lib/services/coins/epiccash/epiccash_wallet.dart b/lib/services/coins/epiccash/epiccash_wallet.dart index b4b264b39..accd6752e 100644 --- a/lib/services/coins/epiccash/epiccash_wallet.dart +++ b/lib/services/coins/epiccash/epiccash_wallet.dart @@ -73,50 +73,6 @@ abstract class ListenerManager { static Pointer? pointer; } -// isolate - -Map isolates = {}; - -Future getIsolate(Map arguments, - {String name = ""}) async { - ReceivePort receivePort = - ReceivePort(); //port for isolate to receive messages. - arguments['sendPort'] = receivePort.sendPort; - Logging.instance.log("starting isolate ${arguments['function']} name: $name", - level: LogLevel.Info); - Isolate isolate = await Isolate.spawn(executeNative, arguments); - isolates[receivePort] = isolate; - return receivePort; -} - -Future executeNative(Map arguments) async { - await Logging.instance.initInIsolate(); - final SendPort sendPort = arguments['sendPort'] as SendPort; - final function = arguments['function'] as String; - try { - Logging.instance.log( - "Error Arguments for $function not formatted correctly", - level: LogLevel.Fatal); - sendPort.send("Error Arguments for $function not formatted correctly"); - } catch (e, s) { - Logging.instance.log( - "An error was thrown in this isolate $function: $e\n$s", - level: LogLevel.Error); - sendPort - .send("Error An error was thrown in this isolate $function: $e\n$s"); - } finally { - await Logging.instance.isar?.close(); - } -} - -void stop(ReceivePort port) { - Isolate? isolate = isolates.remove(port); - if (isolate != null) { - isolate.kill(priority: Isolate.immediate); - isolate = null; - } -} - Future deleteEpicWallet({ required String walletId, required SecureStorageInterface secureStore, @@ -167,13 +123,6 @@ class EpicCashWallet extends CoinServiceAPI initCache(walletId, coin); initEpicCashHive(walletId); initWalletDB(mockableOverride: mockableOverride); - - Logging.instance.log("$walletName isolate length: ${isolates.length}", - level: LogLevel.Info); - for (final isolate in isolates.values) { - isolate.kill(priority: Isolate.immediate); - } - isolates.clear(); } static const integrationTestFlag = @@ -392,10 +341,6 @@ class EpicCashWallet extends CoinServiceAPI timer?.cancel(); timer = null; stopNetworkAlivePinging(); - for (final isolate in isolates.values) { - isolate.kill(priority: Isolate.immediate); - } - isolates.clear(); Logging.instance.log("EpicCash_wallet exit finished", level: LogLevel.Info); } @@ -1461,11 +1406,6 @@ class EpicCashWallet extends CoinServiceAPI timer = null; if (isActive) { unawaited(startSync()); - } else { - for (final isolate in isolates.values) { - isolate.kill(priority: Isolate.immediate); - } - isolates.clear(); } this.isActive = isActive; };